题解 【ZJOI2009】 假期的宿舍
题面
解析
这其实就是个二分图匹配的水题(虽然我还是爆零了)
这题的意思就是说,有x个人,y张床(x,y不确定),
每个人只能睡在指定的几张床上,
问能否使每人都有床睡。
所以,直接二分图匹配,看最大匹配是否大于行了啊啊!(当然,用网络流也可以。)
然而,却出现了一些玄学错误(导致本次考试全体爆零)。
所以,我来总结一下:
- 多组数据要记得清零!
- 注意如果第 i 个人不是在校学生,那么这个位置上的数是一个随机的数,应该在读入以后忽略它
- 连边的时候要住意有些校外的人没床。
然后就能AC了!
上AC代码(虽然感觉没什么用):
#include<bits/stdc++.h> using namespace std; inline int read(){ int sum=0,f=1;char ch=getchar(); while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();} return f*sum; } struct node{ int next,to; }e[100001]; int T; int n,s[1001]/*是否在校*/,a[1001]/*是否回家*/; int m,head[1001],cnt=1; int f[1001][1001]; int linker[1001],vis[1001]; void add(int x,int y){ e[++cnt].to=head[x]; e[cnt].next=y; head[x]=cnt; } bool dfs(int x){ for(int i=head[x];i;i=e[i].to){ int k=e[i].next; if(vis[k]) continue; vis[k]=1; if(linker[k]==-1||dfs(linker[k])){ linker[k]=x; return 1; } } return 0; } bool hungarian(int m){ memset(linker,-1,sizeof(linker)); int sum=0; for(int i=1;i<=n;i++){ if(!a[i]){ memset(vis,0,sizeof(vis)); if(dfs(i)) sum++; } } if(sum>=m) return 1; return 0; } int main(){ // freopen("dormitory.in","r",stdin); // freopen("dormitory.out","w",stdout); T=read(); while(T--){ memset(head,0,sizeof(head)); memset(e,0,sizeof(e)); memset(f,0,sizeof(f)); memset(a,0,sizeof(a)); cnt=1; n=read();m=n; for(int i=1;i<=n;i++) s[i]=read(); for(int i=1;i<=n;i++){ int x=read(); if(s[i]) a[i]=x; } for(int i=1;i<=n;i++) m-=a[i]; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ f[i][j]=read(); } f[i][i]=1; } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(f[i][j]&&s[j]) add(i,j+n); } } if(hungarian(m)) printf("%c%c%c\n",94,95,94); else printf("T_T\n"); } return 0; }