首页 > 其他分享 >题解 [国家集训队] 稳定婚姻

题解 [国家集训队] 稳定婚姻

时间:2023-08-08 11:33:47浏览次数:50  
标签:cnt name int 题解 nd low 婚姻 夫妻 国家集训队

题目链接

首先我们考虑用图论的边描述这个关系。若两者存在夫妻或情侣关系,就连一条边(是有向边还是无向边呢?)。

先来考虑两对夫妻的情况,若夫妻边与情侣边交替出现。且一对夫妻在同一个环内,则可以说明分开后能够重新找到另一半。

如下图:

夫妻
a-男 b-女
c-男 d-女
情侣
a-男 d-女
c-男 b-女


为什么一定要夫妻边和情侣边交替出现呢?因为只有在这种情况下,a可以找到d,b可以找到c,即原来的夫妻全都可以通过相邻的情侣边找到新的另一半。

但是对于不交替出现的情况,显然是不能实现的,这里手搓一下就行。

那么对于夫妻边,建一条由男指向女的边;情侣边,建一条由女指向男的边,这样走出来的一条环就一定是两种边交替出现的。

最后判断一对夫妻是否在同一个强连通分量中即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;

typedef unsigned long long ULL;
typedef long long LL;

const int N=1e5;
int n,m;
string a[N],b[N];
int cnt_name;
map<string,int> name;
int tot=1,nxt[N],to[N],h[N];

void add(int x,int y) {
    to[++tot]=y; nxt[tot]=h[x]; h[x]=tot;
}

int dfn[N],low[N],id[N],fst[N];
int scc_cnt,timestamp;
stack<int> st;

void tarjan(int nd) {
    dfn[nd]=low[nd]=++timestamp;
    st.push(nd); fst[nd]=1;
    for(int i=h[nd];i;i=nxt[i]) {
        int x=to[i];
        if(!dfn[x]) {
            tarjan(x);
            low[nd]=min(low[nd],low[x]);
        }
        else if(fst[x]) low[nd]=min(low[nd],dfn[x]);
    }
    if(dfn[nd]==low[nd]) {
        int y;
        scc_cnt++;
        do {
            y=st.top(); st.pop();
            id[y]=scc_cnt; fst[y]=0;
        } while(y!=nd);
    }
}


int main() {
    // freopen("a.in","r",stdin);
    // freopen("a.out","w",stdout);

    cin>>n;
    for(int i=1;i<=n;i++) {
        cin>>a[i]>>b[i];
        name[a[i]]=++cnt_name;
        name[b[i]]=++cnt_name;
        add(name[a[i]],name[b[i]]);
    }
    cin>>m;
    for(int i=1;i<=m;i++) {
        string x,y; cin>>x>>y;
        add(name[y],name[x]);
    }
    for(int i=1;i<=2*n;i++) {
        if(!dfn[i]) tarjan(i);
    }

    for(int i=1;i<=n;i++) {
        int x=id[name[a[i]]],y=id[name[b[i]]];
        if(x==y) cout<<"Unsafe"<<"\n";
        else cout<<"Safe\n";
    }


    return 0;
}

标签:cnt,name,int,题解,nd,low,婚姻,夫妻,国家集训队
From: https://www.cnblogs.com/zhangyuzhe/p/17613702.html

相关文章

  • 洛谷 CF572B题解
    思路首先,将SELL和BUY交易数据分别存放在两个桶。接下来,从小到大遍历。取出最小的\(s\)个:从大到小遍历,取出最大的\(s\)个。分别存放在queue和stack中,如果不到\(s\)就取完为止。最后,输出queue和stack中的所有元素即可。代码实现:#include<bits/stdc++.h>usi......
  • 题解 [POI2005] SZA-Template
    题目链接充分暴露出对\(border\)结合\(dp\)理解的不足。先来推结论,一个字符串的印章一定是其\(border\),因为只有这样才可能兼顾首尾,但是他的\(border\)不一定是其印章,两个条件不能互推。设\(dp_i\)表示前\(i\)个字符串的最小印章长度。现在考虑如何转移。\(dp_i\)......
  • BZOJ3337 ORZJRY I 题解
    https://vjudge.net/problem/黑暗爆炸-3337题意试维护一个序列,支持以下\(11\)种操作:输入格式说明1xw在\(a_x\)后插入\(w\)2x删除\(a_x\)3xy翻转\((a_x,a_{x+1},\dots,a_y)\)4xyk将\((a_x,a_{x+1},\dots,a_y)\)右移\(k\)次......
  • CF671D Roads in Yusland 题解
    题目链接题目要求我们求出选出若干条路径并最小化花费,如果这是在链上,我们可以考虑直接枚举每条路径的右端点dp,那树呢?把路径剖分整个覆盖的集合就不一定连续了,没法dp,况且题目里给了很强的条件:路径一定是从孩子到祖先,硬转链用不上这个性质,貌似不太对。上述思考启发我们利用树的......
  • “科大国创杯”2023 年安徽省青少年信息学科普日活动 简要题解
    “科大国创杯”2023年安徽省青少年信息学科普日活动简要题解小学组T1grade直接累加即可。不需要按百分比算(也就是别/100),那样可能会出现一些浮点数误差。T2order暴力枚举t就可以了T3string答案即为cnt4+cnt5-cnt20。注意到对于一个数,我们只关心其个位和十位就......
  • 打开电脑中应用程序及问题解决方案
    1、使用os.system()函数:示例代码importosos.system("notepad.exe")这将在Windows系统上打开记事本应用程序。2、使用subprocess示例代码:importsubprocesssubprocess.Popen(['notepad.exe'])3、使用webbrowser示例代码:importwebbrowserwebbrowser.open('http://www.goog......
  • 【题解】 Pattern Matching in A Minor "Low Space" CCPC Mianyang 2022
    https://vjudge.net/contest/573644#problem/K字符串匹配,但卡空间。考虑哈希做法,不妨把\(s\)每\(20000\)个字符哈希成一个字符,于是\(s\)长度只有\(500\),可以跑个KMP。于是对于\(t\),我们只需要同时维护\(20000\)个KMP的指针。但如果字符串长度不是\(20000\)的倍......
  • P9498 「RiOI-2」equals题解
    题目传送门:P9498「RiOI-2」equals-洛谷|计算机科学教育新生态(luogu.com.cn)这是洛谷月赛Div.2T3,由于我比较菜,只能赛场上切到T3(T4是黑。),开题我们很容易就看出这道题首先需要初始化每个点到根节点的最短路,而且边权都为1,所以我们先无脑打一个堆优化的dijkstra,剩下的就是处......
  • P1005 [NOIP2007 提高组] 矩阵取数游戏题解
    题面传送门:P1005[NOIP2007提高组]矩阵取数游戏-洛谷|计算机科学教育新生态(luogu.com.cn)分析题目可知,这道题是一道求最值的问题,第一次看题没有认真读题,以为是每次只在某一行中选一个数,于是想了半天无果。重新读题才发现每次需要每行都取,那么这就很简单了,相当于在每一行......
  • 洛谷 P1336 最佳课题选择 题解
    P1336最佳课题选择题解状态:考虑\(f_{i,j}\)表示前\(i\)种论文里面,一共写了\(j\)篇,的最少花费时间。转移策略:我们一次考虑每一种论文写多少篇。假设写\(k\)篇,\(k\in[0,j]\cap\mathbb{Z}\),有转移方程:\[f_{i,j}=min(f_{i-1,j-k}+cost(i,k)),k\in[0,j]\cap\mathbb{......