##题目大意:
有n个人,分别是:在校的学生,回家的学生,来看望在校学生的学生,有人走了,就有空床,有人来了,就需要床,只能睡自己的床或者直接认识的人的床.
读入有些烦,要仔细看:
第一行一个数 T 表示数据组数。接下来 T 组数据,每组数据第一行一个数n 表示涉及到的总人数。接下来一行 n 个数,第 i 个数表示第 i 个人是否是在校学生 (0 表示不是,1 表示是)。再接下来一行 n 个数,第 i 个数表示第 i 个人是否回家 (0 表示不回家,1 表示回家,注意如果第 i 个人不是在校学生,那么这个位置上的数是一个随机的数,你应该在读入以后忽略它)。接下来 n 行每行 n 个数,第 i 行第 j 个数表示 i 和 j 是否认识 (1 表示认识,0 表示不认识,第 i 行 i 个的值为 0,但是显然自己还是可以睡自己的床),认识的关系是相互的。
##解题思路:
话说这道题还挺难的.
在Codevs还是最高段位(大师)
可以用匈牙利算法,我用Dinic(网络流——最大流)做的.
首先建立源点,汇点,源点连接需要床的人,汇点连接床,然后把人和他可以睡的床连接,再求最大流就可以了.
最重要的是初始化,因为是多组数据
##源程序:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define inf 2147483647
using namespace std;
int Q,n,m,s,t,cnt,last[2001],dis[2001],school[101],home[101],sum;
struct node{int to,next,c;}
e[2005];
queue<int> que;//队列
void add(int u,int v,int c)//邻接表
{
e[cnt].to=v;e[cnt].c=c;e[cnt].next=last[u];last[u]=cnt++;
e[cnt].to=u;e[cnt].c=0;e[cnt].next=last[v];last[v]=cnt++;
}
bool bfs()//bfs找增广路,分层
{
memset(dis,-1,sizeof(dis));//初始化
while (!que.empty()) que.pop();//清空队列
dis[s]=0; que.push(s);//源点进入队列
while (!que.empty())
{
int u=que.front();que.pop();
//把最先进入队列的赋值给u然后出队列
for (int i=last[u];i!=-1;i=e[i].next)
//找增广路,分层
if (e[i].c&&dis[e[i].to]==-1)
{
dis[e[i].to]=dis[u]+1;
if (e[i].to==t) return 1;
//如果到了汇点就说明这是一条增光路呗
que.push(e[i].to);
//当然要进入队列
}
}
return 0;
}
int dfs(int x,int other)
{
if (x==t||!other) return other;
int ret=0;//ret是已用流量,other是总共有的流量
for (int i=last[x];i!=-1;i=e[i].next)
//修改增广路的流量
if (e[i].c&&dis[e[i].to]==dis[x]+1)
{
int f=dfs(e[i].to,min(e[i].c,other-ret));
//接着改
if (!f) dis[e[i].to]=-1;
e[i].c-=f;
e[i^1].c+=f;
//改流量
ret+=f;
//改已用流量
}
if(!ret) dis[x]=-1;
return ret;
}
int dinic()
{
int ans=0;
while (bfs()) ans+=dfs(s,inf);
//找增光路,改流量,计算答案
return ans;
}
int main()
{
scanf("%d",&Q);
for (int q=1;q<=Q;q++)
{
scanf("%d",&n);
cnt=0;
memset(&e,0,sizeof(e));
memset(last,-1,sizeof(last));
s=n<<1|1; t=s+1; sum=0;//初始化
for (int i=1;i<=n;i++)
{scanf("%d",&school[i]);if(school[i]) add(i+n,t,1);}//读入,建边
for (int i=1;i<=n;i++)
{scanf("%d",&home[i]);if(!school[i]||!home[i]) add(s,i,1),sum++;}
//读入,建边,sum统计需要床的人
int flag;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
scanf("%d",&flag);
if(flag||i==j) add(i,j+n,1);
//读入关系,建边
}
int ans=dinic();//赋值
if (sum==ans) printf("^_^\n");
else printf("T_T\n");
//判定是否可以让所有需要床的人都有床睡并输出
}
}