您的位置:首页 > 其它

luogu2055 [ZJOI2009]假期的宿舍

2017-01-08 13:25 295 查看

题目

  https://www.luogu.org/problem/show?pid=2055

题解

  题目很简单就是有点绕。。

  读懂了题大概就会做了,让i表示i这个人,N+i表示这个人的床。如果i认识j且j是在校生,就连一条i->N+j的边,容量为1;然后每个需要在学校睡觉的人从S连向它,容量为1;每张床连向T,容量为1,统计一下有多少人需要在学校睡觉,再看看和最大流是不是相等就行了。

代码

//最大流
#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 100000
using namespace std;
int N, cases, next[maxn], head[maxn], tot=1, to[maxn], c[maxn], d[maxn], num[maxn],
Exit, last[maxn], S, T, rl[100][100], inschool[maxn], gohome[maxn], cnt;
void adde(int a, int b, int v){to[++tot]=b;c[tot]=v;next[tot]=head[a];head[a]=tot;}
void adde2(int a, int b, int v){adde(a,b,v);adde(b,a,0);}
int ISAP(int pos, int in)
{
int t, p, flow=0;
if(pos==T)return in;
for(p=last[pos];p;last[pos]=p=next[p])
if(c[p] and d[pos]==d[to[p]]+1)
{
flow+= t=ISAP(to[p],min(in-flow,c[p]));
c[p]-=t, c[p xor 1]+=t;
if(Exit or in==flow)return flow;
}
Exit = --num[d[pos]]==0;
++num[++d[pos]];
last[pos]=head[pos];
return flow;
}
void init()
{
memset(head,0,sizeof(head));
memset(next,0,sizeof(next));
memset(last,0,sizeof(last));
memset(d,0,sizeof(d));
memset(num,0,sizeof(num));
memset(rl,0,sizeof(rl));
tot=1, Exit=0, cnt=0;
int i, j, x;
scanf("%d",&N);
S=N+N+1, T=S+1;
for(i=1;i<=N;i++)scanf("%d",inschool+i);
for(i=1;i<=N;i++)scanf("%d",gohome+i);
for(i=1;i<=N;i++)for(j=1;j<=N;j++)
{
scanf("%d",&x);
if((x and inschool[j]) or i==j)adde2(i,N+j,1);
}
for(i=1;i<=N;i++)
{
if(!(inschool[i] and gohome[i]))adde2(S,i,1),cnt++;
if(inschool[i])adde2(N+i,T,1);
}
}
int main()
{
int flow;
scanf("%d",&cases);
while(cases--)
{
init();
flow=0;
while(!Exit)flow+=ISAP(S,0x7fffffff);
if(flow==cnt)printf("^_^\n");else printf("T_T\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: