Description
题解:
水题,然而wa了n次因为忘记自己可以睡自己的床。
不过还是在30min内A了,
把每个点拆成两个,
st连向所有需要床位的人,
所有床位连向ed,
如果ij认识就连一条边。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define inf 1e9
using namespace std;
const int N=7001;
int t,n;
int st,ed=1001;
struct node{
int x,y,z,next,other;
}sa[N<<1];int len=0,first[N];
void ins(int x,int y,int z)
{
len++;
sa[len].x=x;
sa[len].y=y;
sa[len].z=z;
sa[len].next=first[x];
first[x]=len;
sa[len].other=len+1;
len++;
sa[len].x=y;
sa[len].y=x;
sa[len].z=0;
sa[len].next=first[y];
first[y]=len;
sa[len].other=len-1;
}
queue<int>q;
int h[N];
bool bt()
{
memset(h,0,sizeof(h));h[st]=1;
q.push(st);
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=first[x];i!=-1;i=sa[i].next)
{
int y=sa[i].y;
if(sa[i].z>0&&h[y]==0)
{
h[y]=h[x]+1;
q.push(y);
}
}
}
if(h[ed]==0) return false;
return true;
}
int getans(int x,int f)
{
if(x==ed) return f;
int s=0,o;
for(int i=first[x];i!=-1;i=sa[i].next)
{
int y=sa[i].y;
if(sa[i].z>0&&h[y]==h[x]+1&&f>s)
{
o=getans(y,min(f-s,sa[i].z));
s+=o;
sa[i].z-=o;
sa[sa[i].other].z+=o;
}
}
if(s==0) h[x]=0;
return s;
}
int sch[N];
int main()
{
scanf("%d",&t);
while(t--)
{
len=0;
memset(first,-1,sizeof(first));
scanf("%d",&n);
int x;
st=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&sch[i]);
if(sch[i]) ins(i+n,ed,1);
}
int yu=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
if(!sch[i]||(x!=1&&sch[i])) ins(st,i,1),yu++;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&x);
if(x==1||i==j) ins(i,j+n,1);
}
}
int ans=0;
while(bt())
{
ans+=getans(st,inf);
}
if(ans>=yu) printf("^_^\n");
else printf("T_T\n");
}
}