洛谷 P2055 [ZJOI2009] 假期的宿舍
題目描述
學校放假了 · · · · · · 有些同學回家了,而有些同學則有以前的好朋友來探訪,那麼住宿就是一個問題。比如 A 和 B 都是學校的學生,A 要回家,而 C 來看B,C 與 A 不認識。我們假設每個人只能睡和自己直接認識的人的床。那麼一個解決方案就是 B 睡 A 的床而 C 睡 B 的床。而實際情況可能非常複雜,有的人可能認識好多在校學生,在校學生之間也不一定都互相認識。我們已知一共有 n 個人,並且知道其中每個人是不是本校學生,也知道每個本校學生是否回家。問是否存在一個方案使得所有不回家的本校學生和來看他們的其他人都有地方住。
輸入輸出格式
輸入格式:第一行一個數 T 表示資料組數。接下來 T 組資料,每組資料第一行一個數n 表示涉及到的總人數。接下來一行 n 個數,第 i 個數表示第 i 個人是否是在校學生 (0 表示不是,1 表示是)。再接下來一行 n 個數,第 i 個數表示第 i 個人是否回家 (0 表示不會家,1 表示回家,注意如果第 i 個人不是在校學生,那麼這個位置上的數是一個隨機的數,你應該在讀入以後忽略它)。接下來 n 行每行 n 個數,第 i 行第 j 個數表示 i 和 j 是否認識 (1 表示認識,0 表示不認識,第 i 行 i 個的值為 0,但是顯然自己還是可以睡自己的床),認識的關係是相互的。
對於每組資料,如果存在一個方案則輸出 “ ˆ_ˆ ”(不含引號) 否則輸出“T_T”(不含引號)。(注意輸出的都是半形字元,即三個符號的 ASCII 碼分別為94,84,95)
輸入輸出樣例
輸入樣例#1:1 3 1 1 0 0 1 0 0 1 1 1 0 0 1 0 0輸出樣例#1:
ˆ_ˆ
說明
對於 30% 的資料滿足 1 ≤ n ≤ 12。
對於 100% 的資料滿足 1 ≤ n ≤ 50,1 ≤ T ≤ 20。
多組資料!!!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
匈牙利演算法+思路~
對於每一個在校的人,與他可以睡的床連邊,這裡床和人都記為點,匹配的時候統一匹配;比如第i個人的床就是第i+n號,不是學生也有床,只不過不連邊。
注意在校的有床的學生要和自己的床連邊!不然WA到飛起!
#include<cstdio> #include<cstring> int t,n,k,ans[101],tot; bool b[51],c[51],kkz[101][101],vis[101],flag; char s[3]={84,94,95}; bool col(int u) { for(int i=1;i<=2*n;i++) if(kkz[u][i] && !vis[i]) { vis[i]=1; if(!ans[i] || col(ans[i])) { ans[i]=u;return 1; } } return 0; } int main() { scanf("%d",&t); while(t--) { memset(ans,0,sizeof(ans)); memset(kkz,0,sizeof(kkz)); scanf("%d",&n);flag=0; for(int i=1;i<=n;i++) scanf("%d",&b[i]); for(int i=1;i<=n;i++) scanf("%d",&c[i]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%d",&k); if(k && i!=j) { if(b[j] && ((b[i] && !c[i]) || !b[i])) kkz[i][j+n]=kkz[j+n][i]=1; if(b[i] && ((b[j] && !c[j]) || !b[j])) kkz[j][i+n]=kkz[i+n][j]=1; } } for(int i=1;i<=n;i++) if(b[i] && !c[i]) kkz[i][i+n]=kkz[i+n][i]=1; for(int i=1;i<=n;i++) if((b[i] && !c[i]) || !b[i]) { memset(vis,0,sizeof(vis)); if(!col(i)) { flag=1;break; } } if(!flag) printf("%c%c%c\n",s[1],s[2],s[1]); else printf("%c%c%c\n",s[0],s[2],s[0]); } return 0; }