题目
https://www.luogu.org/problemnew/show/P2055
思路
这题可以用二分图最大匹配,也可以用网络流。
这是网络流的做法
建图
把所有床跟汇点连边(及在校学生的床)(用i+n表示),把所有需要床的人与源点连边。把认识的人连边。权值均为一。
做法
跑dinic。
注意
这里有多组数据,所以要初始化。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 6777
using namespace std;
struct E
{
int to,c,next;
}e[maxn];
int cur[maxn],dis[maxn],list[maxn],cnt=1,n,a[maxn],b[maxn],s,t;
void add(int u,int v,int x)
{
e[++cnt].to=v; e[cnt].c=x; e[cnt].next=list[u]; list[u]=cnt;
e[++cnt].to=u; e[cnt].c=0; e[cnt].next=list[v]; list[v]=cnt;
}
bool bfs()
{
memset(dis,0,sizeof(dis));
queue<int> q;
dis[0]=1; q.push(0);
while(!q.empty())
{
int u=q.front(); q.pop();
for(int i=list[u]; i; i=e[i].next)
{
if(e[i].c&&!dis[e[i].to])
{
dis[e[i].to]=dis[u]+1;
if(e[i].to==t) return 1;
q.push(e[i].to);
}
}
}
return 0;
}
int dfs(int x,int maxf)
{
if(x==t||!maxf) return maxf;
int ret=0;
for(int &i=cur[x]; i; i=e[i].next)
{
if(e[i].c&&dis[e[i].to]==dis[x]+1)
{
int f=dfs(e[i].to,min(maxf-ret,e[i].c));
e[i].c-=f; e[i^1].c+=f;
ret+=f;
if(maxf==ret) break;
}
}
return ret;
}
int dinic()
{
int ass=0;
while(bfs())
{
for(int i=s; i<=t; i++) cur[i]=list[i];
ass+=dfs(s,0x3f3f3f3f);
}
return ass;
}
int main()
{
int p;
scanf("%d",&p);
while(p--)
{
cnt=1;
memset(e,0,sizeof(e));
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(list,0,sizeof(list));
memset(cur,0,sizeof(cur));
int ss=0;
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,1);
}
for(int i=1; i<=n; i++)
{
scanf("%d",&b[i]);
if(!a[i]) b[i]=0;
if(!b[i]) add(s,i,1);
if(!b[i]) ss++;
}
for(int i=1; i<=n; i++) for(int j=1; j<=n; j++)
{
int x;
scanf("%d",&x);
if(x) add(i,j+n,1);
if(i==j) add(i,j+n,1);
}
if(dinic()==ss) printf("^_^\n");else printf("T_T\n");
}
}