题意
有几个同学要来盼望在学校里的同学,他们希望他们和学校里的同学都有床睡,其中一个人只能睡他认识的人的床或自己的床。现在给出每个同学是否在校生和是否回家的情况,以及它们认识的情况,求出它们能否全部人都有床睡。
思路
这道题构好图然后跑一边最大流。让有床的人和汇点连接,需要床的人和源点连接,然后他们如果互相认识就让他们连接。
代码
#include<cstdio>
#include<cstring>
#include<queue>
#define min(a,b) a<b?a:b
using namespace std;
int tot,t,n,S,T,x,head[101],d[101],f,ans,sum;bool a[51];
struct node{
int to,next,v;
}e[1001];
void add(int x,int y)
{
e[++tot].to=y;e[tot].next=head[x];e[tot].v=1;
head[x]=tot;
e[++tot].to=x;e[tot].next=head[y];e[tot].v=0;
head[y]=tot;
}
bool bfs()
{
memset(d,0,sizeof(d));
int v;
queue<int>q;
d[S]=1;q.push(S);
while (q.size())
{
v=q.front();q.pop();
for (int i=head[v];i!=-1;i=e[i].next)
{
int y=e[i].to;
if (d[y]==0&&e[i].v)
{
d[y]=d[v]+1;
q.push(y);
if (y==T) return 1;
}
}
}
return 0;
}
int dfs(int k,int flow)
{
if (k==T) return flow;
int rest=0,w;
for (int i=head[k];i!=-1;i=e[i].next)
{
if (e[i].v&&d[k]+1==d[e[i].to])
{
w=dfs(e[i].to,min(e[i].v,flow-rest));
if (!w) d[e[i].to]=0;
e[i].v-=w;
e[i^1].v+=w;
rest+=w;
}
}
return rest;
}
int main()
{
scanf("%d",&t);
while (t--)
{
memset(head,-1,sizeof(head));
ans=sum=0;
tot=1;
scanf("%d",&n);
S=0;T=2*n+1;
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if (a[i]) add(i+n,T);//在校生有床就和汇点连接
}
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
if(!x||!a[i])
{
add(S,i);//需要床的
ans++;//记录需要床的人数
}
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
scanf("%d",&x);
if (x||i==j) add(i,j+n);//相互认识还有睡自己床的
}
}
while (bfs())
while (f=dfs(S,2147483647)) sum+=f;//求出最大流
if (sum==ans) printf("^_^\n");//判断是否够床
else printf("T_T\n");
}
}