【tarjan】BZOJ2140-稳定婚姻
又名NTR的故事
【题目大意】
n对夫妻Bi和Gi。若某男Bi与某女Gj曾经交往过,他们有私奔的可能性。不妨设Bi和Gj旧情复燃,进而Bj会联系上了他的初恋情人Gk,以此递推。若在Bi和Gi离婚的前提下,这2n个人最终依然能够结合成n对情侣,那么我们称婚姻i为不安全的,否则婚姻i就是安全的。问n对夫妻的婚姻分别是安全的吗?
【思路】
第一反应是匈牙利算法,但是太过于暴力了,过不了。
我们把夫妻中女方连向男方,旧情中男方连向女方。可以得出结论:如果该有向图的强连通分量中,夫妻双方在同一个强连通分量里,那么他们的婚姻是不安全的,否则他们的婚姻是安全的。
为什么呢?如果在同一个强连通分量中,显然可以连出一个增广路,相当于匈牙利算法可以跑,那么必定是能形成新的n对情侣的。
如果不在一个强连通分量中,可以理解为匈牙利算法不能调整了(具体原因见匈牙利算法),那么必定不能形成新的n对情侣。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<map> 6 #include<vector> 7 #include<stack> 8 using namespace std; 9 map<string,int> Name; 10 const int MAXN=4000+50; 11 int n,m; 12 int cnt,col,dfn[MAXN*2],low[MAXN*2],instack[MAXN*2],tar[MAXN*2]; 13 vector<int> E[MAXN*2]; 14 stack<int> S; 15 16 void addedge(int u,int v){E[u].push_back(v);} 17 18 void tarjan(int u) 19 { 20 low[u]=dfn[u]=++cnt; 21 S.push(u); 22 instack[u]=1;//不要忘记了这两句 23 for (int i=0;i<E[u].size();i++) 24 { 25 int v=E[u][i]; 26 if (!instack[v]) 27 { 28 tarjan(v); 29 low[u]=min(low[u],low[v]); 30 } 31 else if (instack[v]==1) low[u]=min(low[u],dfn[v]); 32 } 33 34 if (low[u]==dfn[u]) 35 { 36 ++col; 37 while (S.top()!=u) 38 { 39 tar[S.top()]=col,instack[S.top()]=2; 40 S.pop(); 41 } 42 tar[u]=col,instack[u]=2; 43 S.pop(); 44 } 45 } 46 47 void init() 48 { 49 scanf("%d",&n); 50 for (int i=1;i<=n;i++) 51 { 52 char wife[15],husband[15]; 53 scanf("%s%s",wife,husband); 54 Name[wife]=i; 55 Name[husband]=i+n; 56 addedge(i,i+n); 57 } 58 scanf("%d",&m); 59 for (int i=1;i<=m;i++) 60 { 61 char Exgf[15],Exbf[15]; 62 scanf("%s%s",Exgf,Exbf); 63 int exgf=Name[Exgf],exbf=Name[Exbf]; 64 addedge(exbf,exgf); 65 } 66 } 67 68 void solve() 69 { 70 cnt=col=0; 71 while (!S.empty()) S.pop(); 72 memset(instack,0,sizeof(instack)); 73 for (int j=1;j<=2*n;j++) if (!instack[j]) tarjan(j); 74 for (int i=1;i<=n;i++) 75 if (tar[i]==tar[i+n]) puts("Unsafe"); 76 else puts("Safe"); 77 } 78 79 int main() 80 { 81 init(); 82 solve(); 83 return 0; 84 }