最喜欢这样的题了(最近越来越发现自己对图论的热爱)~
也可能是因为这种题好写。。。
但是对自己没有一次AC表示不舒服。
原因是数组开小了(emmm……)……
言归正传:
首先是图的存法,由于要够成环,所以夫妻之间的边和情侣之间的边方向一定是相反的(因为对于无向图的写法我没太大把握),至于具体方向无所谓,只要相反,就行。
然后我们的可爱的Tarjan一遍遍地跑呀跑……
看一遍,如果情侣在一个强连通分量里,自然就是不安全的,反之安全。
有一个小技巧:
一开始我是枚举边并且判断是否为情侣,还要开数组记下来谁是谁的情侣,判断很麻烦。
切掉之后我看了一眼题解,发现意外收获:就是我们可以规定一对情侣之间的序号相差n(这样肯定没有重叠嘛),这样判断的时候,判断 i 和 i + n 即可。
好了直接上代码:
#include<cstdio> #include<iostream> #include<map> using namespace std; #define maxn 500005 int low[50000],dfn[50000],head[50000],co[50000],to[maxn],nxt[maxn],st[maxn]; int cnt,n,m,col,num,top; map<string,int> q; void add(int a,int b) { to[++cnt]=b; nxt[cnt]=head[a]; head[a]=cnt; } void Tarjan(int u) { dfn[u]=low[u]=++num; st[++top]=u; for(int i=head[u];i;i=nxt[i]) { int v=to[i]; if(!dfn[v]) { Tarjan(v); low[u]=min(low[u],low[v]); } else if(!co[v]) low[u]=min(dfn[v],low[u]); } if(low[u]==dfn[u]) { co[u]=++col; while(st[top]!=u) { co[st[top]]=col; top--; } top--; } } int main() { scanf("%d",&n); string gir,boy; for(int i=1;i<=n;i++) { cin>>gir>>boy; q[gir]=i; q[boy]=i+n; add(i,i+n); } scanf("%d",&m); for(int i=1;i<=m;i++) { cin>>gir>>boy; add(q[boy],q[gir]); } for(int i=1;i<=2*n;i++) if(!dfn[i]) Tarjan(i); for(int i=1;i<=n;i++) if(co[i]==co[i+n]) printf("Unsafe "); else printf("Safe "); return 0; }