正题
链接:
https://www.luogu.org/record/show?rid=7930976
大意
有n个人,有的在学校有床有的没有,有的在家有的没有。现在如果有人回家了那么他就会去看望他的朋友,回家的就会空出自己的床位。每个人可以睡和自己是直接朋友关系或自己的床,要求给本来有床的并且不在家的和来看望其的朋友分配床位。
解题思路
将人和床建立二分图,我们假设每个在家的人都有床,这样不用看望朋友的就可以睡自己床,然后将除了没有床且不再家的人都作为左边点,然后将在学校的床作为右边点进行最大匹配。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct line{int to,next,w;
}a[10010];
int n,m,x,y,d[110],tot,state[110],school[110],num;
int head,tail,ls[110],s,e,ans,t,home[110],nn,qn;
bool ok[110],lxx[110][110];
void addl(int x,int y,int w)
{a[tot].to=y;a[tot].next=ls[x];a[tot].w=w;ls[x]=tot++;a[tot].to=x;a[tot].next=ls[y];a[tot].w=0;ls[y]=tot++;
}
bool bfs()
{head=0;tail=1;memset(d,-1,sizeof(d));d[s]=0;state[1]=s;do{head++;int x=state[head];for (int q=ls[x];q;q=a[q].next){int y=a[q].to;if (a[q].w>0 && d[y]==-1){d[y]=d[x]+1;state[++tail]=y;if (y==e) return true;}}}while (head<tail);return false;
}
int dinic(int x,int flow)
{int rest=0,k;if (x==e) return flow;for (int q=ls[x];q;q=a[q].next){int y=a[q].to;if (a[q].w>0 && d[y]==d[x]+1){rest+=(k=dinic(y,min(a[q].w,flow-rest)));a[q].w-=k;a[q^1].w+=k;if (rest==flow) return flow;}}if (!rest) d[x]=0;return rest;
}
int main()
{scanf("%d",&t);for (int ti=1;ti<=t;ti++){memset(ls,0,sizeof(ls));e=105;s=104;tot=2;num=0;scanf("%d",&n);for (int i=1;i<=n;i++){scanf("%d",&school[i]);if(school[i]) addl(i+n,e,1);//床}for (int i=1;i<=n;i++){scanf("%d",&home[i]);if (!school[i]||(school[i]&&!home[i])) addl(s,i,1),num++;//需要匹配的人}for (int i=1;i<=n;i++){for (int j=1;j<=n;j++){scanf("%d",&x);if (x||i==j)addl(i,j+n,1);//和自己或直接朋友的床匹配}}ans=0;while (bfs()) ans+=dinic(s,2147483647);if (ans==num) printf("^_^\n");else printf("T_T\n");}
}
小技巧
其实有些时候可以将本来不需要的在其他地方分配掉可能可以降低难度