Description
Input
Output
Sample Input
1
3
1 1 0
0 1 0
0 1 1
1 0 0
1 0 0
3
1 1 0
0 1 0
0 1 1
1 0 0
1 0 0
Sample Output
ˆ ˆ
HINT
对于30% 的数据满足1 ≤ n ≤ 12。
对于100% 的数据满足1 ≤ n ≤ 50,1 ≤ T ≤ 20。
正解:二分图匹配(匈牙利算法)
解题报告:
直接跑匈牙利算法。注意连边的关系,只有当i需要床位而且j可能提供床位时才连边,而且i不回家时,向自己连边。
注意最大匹配的时候vis数组不能记i本身,因为可以匹配自己。细节问题。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int MAXN = 51; 21 int n,ans,cnt,a[MAXN][MAXN],b[MAXN],c[MAXN],match[MAXN]; 22 bool vis[MAXN]; 23 24 inline int getint() 25 { 26 int w=0,q=0; 27 char c=getchar(); 28 while((c<'0' || c>'9') && c!='-') c=getchar(); 29 if (c=='-') q=1, c=getchar(); 30 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); 31 return q ? -w : w; 32 } 33 34 inline bool dfs(int x){ 35 //不能加这一步!!!可能会匹配自己!!! 36 //vis[x]=1 37 for(int i=1;i<=n;i++) { 38 if(a[x][i] && !vis[i]) { 39 vis[i]=1; 40 if(!match[i] || dfs(match[i])) { 41 match[i]=x; 42 // match[x]=i;不能标记两边 43 return true; 44 } 45 } 46 } 47 return false; 48 } 49 50 inline void work(){ 51 int T=getint(); 52 while(T--) { 53 memset(a,0,sizeof(a));memset(match,0,sizeof(match)); 54 n=getint(); ans=0; cnt=0; 55 for(int i=1;i<=n;i++) b[i]=getint(); for(int i=1;i<=n;i++) c[i]=getint(); 56 for(int i=1;i<=n;i++) if(!b[i] || (b[i]&&!c[i])) cnt++;//统计需要床位的人数 57 int x; 58 for(int i=1;i<=n;i++) { 59 for(int j=1;j<=n;j++) { 60 x=getint(); 61 if(x && ((b[i] && !c[i]) || !b[i] ) &&b[j]) //表示i需要床位,而且i、j认识,并且j可能提供床位 62 a[i][j]=1; 63 } 64 if(b[i] && !c[i]) a[i][i]=1;//留校的在校生肯定可以睡自己床上 65 } 66 for(int i=1;i<=n;i++) { 67 memset(vis,0,sizeof(vis)); 68 if(dfs(i)) ans++; 69 } 70 if(ans==cnt) printf("^_^ "); 71 else printf("T_T "); 72 } 73 } 74 75 int main() 76 { 77 work(); 78 return 0; 79 }