1. 程式人生 > >P1407 [國家集訓隊]穩定婚姻

P1407 [國家集訓隊]穩定婚姻

  最喜歡這樣的題了(最近越來越發現自己對圖論的熱愛)~

  也可能是因為這種題好寫。。。

  但是對自己沒有一次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\n"); else printf("Safe\n"); return 0; }