題意:國王有n個兒子,現在有n個美女,每個兒子都有若干個夢中情人,現在已經有一個方案使每個王子都能與自己的夢中情人之一結婚。現在要求的是,對于每個兒子能選擇的配偶是誰(最終每個兒子都能結成婚)?
分析:這個題的建圖方法很特別。為了充分利用條件,即最后給出的那個完美匹配,將每個王子向他的夢中情人作一條有向邊,完美匹配方案中,美女向匹配的王子作一條有向邊。求出圖中的強連通分量,與王子在同一個強連通分量且該王子喜歡的美女就是答案。
正確性:王子集合{x1,x2,......,xn},美女集合{y1,y2,......,yn},假設在原完美匹配方案中每個匹配都是(xi,yi),顯然yi是xi的一個選項。假如xi選了yj(j!=i),則原先與yj匹配的王子xj要找另一個女人,yi要與另一個王子匹配,假如xj喜歡yi,那么yj就可以是xi的另一個選項了,假如xj不喜歡yi,那么就繼續下去拆散現有的完美匹配,直到有個王子喜歡yi。所以這樣就相當于要找一條由xi出發到yi的通路(等價于由xi出發回到xi的回路),只要這樣的回路存在,王子就可以與回路中任意一個他喜歡的美女匹配了。這樣也就相當于求包含xi的強連通分量。(注意:求出強連通分量之后,只有王子喜歡的美女才能匹配)。
1 #include<cstdio> 2 #include<vector> 3 #include<stack> 4 #include<algorithm> 5 using namespace std; 6 stack<int> s; 7 vector<int> arc[5005],group[5005]; 8 bool visited[5005],instack[5005],matrix[2001][2001]; 9 int counter,low[5005],num[5005],sn,set[5005],n; 10 void tarjan(int u) 11 { 12 int i,v; 13 num[u]=low[u]=++counter; 14 visited[u]=true; 15 instack[u]=true; 16 s.push(u); 17 for(i=0;i<arc[u].size();i++) 18 { 19 v=arc[u][i]; 20 if(!visited[v]) 21 { 22 tarjan(v); 23 low[u]=min(low[v],low[u]); 24 } 25 else if(instack[v]) 26 low[u]=min(low[u],num[v]); 27 } 28 if(num[u]==low[u]) 29 { 30 do 31 { 32 v=s.top(); 33 if(v>n)//v is a girl 34 group[sn].push_back(v); 35 else 36 set[v]=sn; 37 instack[v]=false; 38 s.pop(); 39 }while(u!=v); 40 sort(group[sn].begin(),group[sn].end()); 41 sn++; 42 } 43 } 44 int main() 45 { 46 while(~scanf("%d",&n)) 47 { 48 for(int i=1;i<=n;i++) 49 { 50 for(int j=1;j<=n;j++) 51 matrix[i][j]=false; 52 } 53 for(int i=1;i<=n;i++) 54 { 55 int m; 56 scanf("%d",&m); 57 for(int j=0;j<m;j++) 58 { 59 int v; 60 scanf("%d",&v); 61 matrix[i][v]=true; 62 arc[i].push_back(v+n); 63 } 64 } 65 for(int i=1;i<=n;i++) 66 { 67 int u; 68 scanf("%d",&u); 69 arc[u+n].push_back(i); 70 } 71 for(int i=1;i<=2*n;i++) 72 instack[i]=visited[i]=false; 73 sn=counter=0; 74 for(int i=1;i<=n;i++) 75 { 76 if(!visited[i]) 77 tarjan(i); 78 } 79 for(int i=1;i<=n;i++) 80 { 81 vector<int> ans; 82 for(int j=0;j<group[set[i]].size();j++) 83 { 84 if(matrix[i][group[set[i]][j]-n]) 85 ans.push_back(group[set[i]][j]-n); 86 } 87 printf("%d",ans.size()); 88 for(int j=0;j<ans.size();j++) 89 printf(" %d",ans[j]); 90 printf("\n"); 91 ans.clear(); 92 } 93 for(int i=1;i<=2*n;i++) 94 arc[i].clear(); 95 for(int i=0;i<sn;i++) 96 group[i].clear(); 97 } 98 return 0; 99 }
?