正题
第三题:[ZJOI2009]假期的宿舍
这道题根据题意我们可以发现,一部分人有床,一部分人没有床,一部分人需要床,一部分人不需要床。然而那些人有洁癖,只会睡在自己的或者认识的人的床。
那么很明显我们就想到了二分图最大匹配。把有床的人和需要床的人的集合分为左右两个集合,那么很明显有床的人可以贡献一的流量(一张床),而需要床的人需要享受一的流量(一张床),所以构图方法就显然了,从begin到每个有床的人建一条流量为1的边,从每个需要床的人到end建一条流量为1的边,然后中间认识的人建一条边即可。这道题跟飞行员匹配问题有点像
#include
#include
#include
#include
using namespace std;
int n;
struct edge{
int y,next,c;
}s[100010];
int first[1010];
int h[1010];
int t;
int len=1;
int begin,end;
bool tf[1010];
queue f;
void ins(int x,int y,int c){
len++;
s[len].y=y;s[len].c=c;s[len].next=first[x];first[x]=len;
len++;
s[len].y=x;s[len].c=0;s[len].next=first[y];first[y]=len;
}
bool bfs(){
f.push(begin);
memset(h,-1,sizeof(h));
h[begin]=1;
while(!f.empty()){
int x=f.front();
f.pop();
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(h[y]==-1 && s[i].c>0){
h[y]=h[x]+1;
f.push(y);
}
}
}
return h[end]!=-1;
}
int dfs(int x,int t){
if(x==end) return t;
int tot=0;
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(tot==t) return t;
if(h[y]==h[x]+1 && s[i].c>0){
int my=dfs(y,min(t-tot,s[i].c));
tot+=my;s[i].c-=my;s[i^1].c+=my;
}
}
if(tot==0) h[x]=0;
return tot;
}
int max_flow(){
int tot=0;
while(bfs()){
int dx=dfs(begin,1e9);
while(dx!=0){
tot+=dx;
dx=dfs(begin,1e9);
}
}
return tot;
}
int main(){
scanf("%d",&t);
while(t--){
len=1;
memset(first,0,sizeof(first));
scanf("%d",&n);
memset(tf,false,sizeof(tf));
begin=0,end=2*n+1;
int tt=0;
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
if(x==1) {
tf[i]=true;
ins(n+i,end,1);
}
}
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
if(x==1 && tf[i]==true) tt++;
else ins(begin,i,1);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
int x;
scanf("%d",&x);
if(i==j || x==1) ins(i,j+n,1);
}
if(max_flow()==n-tt) printf("^_^\n");
else printf("T_T\n");
}
}