一道网络有关的问题,还是一句话
网络流重在建模!
这里主要讲两种算法。
1.二分图匹配:
分析题意,我们可以知道题目要求是让所有留在学校的人都能有床睡
而 所有留在学校的人=本校不回家的人+外校的人;
床的总量=所有本校生的数量;
理解题意后,我们考虑将所有人的情况拆开来考虑,即:
每个人有两个信息:人和他的床(如果他有的话)
将人编号1~n,那么床就是n+1~2*n(人的编号加上n即为床的编号)
那么只要两人之间有关系,就可以对应的将他们的人和床之间连一条无权值的边
再找到所有留在学校的人分别跑匈牙利算法,看看是否存在最大匹配=所有留在学校的人数
可以根据样例理解一下:
其中红色的表示需要床的人,绿色表示可用的床
注意不要忘记对于不回家的本校生和他自己的床之间连一条边
CODE
#include<cstdio> #include<cstring> using namespace std; const int N=55,INF=1e9; struct edge { int to,next; }e[N*N*10]; int head[N*2],from[N*2],ti,n,i,j,k,x,tot,sum; bool sch[N*2],need[N*2],vis[N*2]; inline void read(int &x) { x=0; char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); } inline void add(int x,int y) { e[++k].to=y; e[k].next=head[x]; head[x]=k; } inline bool find(int now) { for (int i=head[now];i!=-1;i=e[i].next) if (!vis[e[i].to]&&sch[e[i].to-n]) { vis[e[i].to]=1; if (!from[e[i].to]||find(from[e[i].to])) { from[e[i].to]=now; return 1; } } return 0; } int main() { read(ti); while (ti--) { memset(e,-1,sizeof(e)); memset(head,-1,sizeof(head)); memset(sch,0,sizeof(sch)); memset(need,0,sizeof(need)); memset(from,0,sizeof(from)); read(n); k=tot=sum=0; for (i=1;i<=n;++i) { read(x); if (x) sch[i]=1; } for (i=1;i<=n;++i) { read(x); if (sch[i]&&!x) need[i]=1,add(i,i+n),++tot; if (!sch[i]) need[i]=1,++tot; } for (i=1;i<=n;++i) for (j=1;j<=n;++j) { read(x); if (x) add(i,j+n); } for (i=1;i<=n;++i) if (need[i]) { memset(vis,0,sizeof(vis)); sum+=find(i); } puts(sum==tot?"^_^":"T_T"); } return 0; }
2.最大流
和上面的算法很类似,就是设置一个超级源点S,一个超级汇点T
由S向所有需要的人连一条边,所有可用的床向T连一条边,然后跑S到T最大流即可
思路和上面类似
CODE
#include<cstdio> #include<cstring> using namespace std; const int N=55,INF=1e9; struct edge { int to,next,c; }e[N*N*10]; int head[N*2],dep[N*2],q[N*10],ti,n,i,j,k,x,s,t,tot; bool h[N*2]; inline void read(int &x) { x=0; char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); } inline void add(int x,int y,int z) { e[++k].to=y; e[k].c=z; e[k].next=head[x]; head[x]=k; } inline int min(int a,int b) { return a<b?a:b; } inline bool BFS() { memset(dep,0,sizeof(dep)); dep[s]=1; q[1]=s; int H=0,T=1; while (H<T) { int now=q[++H]; for (int i=head[now];i!=-1;i=e[i].next) if (!dep[e[i].to]&&e[i].c) { dep[e[i].to]=dep[now]+1; q[++T]=e[i].to; } } return dep[t]; } inline int DFS(int now,int dist) { if (now==t) return dist; int res=0; for (int i=head[now];i!=-1&&dist;i=e[i].next) if (dep[e[i].to]==dep[now]+1&&e[i].c) { int dis=DFS(e[i].to,min(dist,e[i].c)); dist-=dis; res+=dis; e[i].c-=dis; e[i^1].c+=dis; } if (!res) dep[now]=0; return res; } inline int Dinic() { int sum=0; while (BFS()) sum+=DFS(s,INF); return sum; } int main() { read(ti); while (ti--) { memset(e,-1,sizeof(e)); memset(head,-1,sizeof(head)); memset(h,0,sizeof(h)); read(n); k=-1; s=tot=0; t=2*n+1; for (i=1;i<=n;++i) { read(x); if (x) add(i+n,t,1),add(t,i+n,0),h[i]=1; } for (i=1;i<=n;++i) { read(x); if (!h[i]||(h[i]&&!x)) add(s,i,1),add(i,s,0),++tot; } for (i=1;i<=n;++i) for (j=1;j<=n;++j) { read(x); if (x||i==j) add(i,j+n,1),add(j+n,i,0); } if (Dinic()==tot) puts("^_^"); else puts("T_T"); } return 0; }