您的位置:首页 > 其它

【BZOJ1433】【codevs2347】假期的宿舍,最大流

2016-05-04 07:40 465 查看
传送门1

传送门2

写在前面:蛤蛤

思路:

(要拆点啊!naive的我一开始没拆点竟然还过了4个点)

每个人拆成两个点,一个在源点那里,一个在汇点那里

1.s连本校学生,容量为1的边(发床了)

2.没回家的本校学生和外面的人往t连容量为1的边(需要床睡觉)

3.认识的人(包括自己的点)之间连容量为1的边

跑出最大流,判断其是否与需要的床数相等即可

注意:拆点啊!拆点

代码:

#include<bits/stdc++.h>
using namespace std;
int n,tot,s,t,T;
int first[125],dis[125];
bool a[65];
struct edge
{
int v,w,next;
}e[100000];
void add(int x,int y,int z){e[++tot]=(edge){y,z,first[x]};first[x]=tot;}
queue<int>q;
bool bfs()
{
memset(dis,0,sizeof(dis));
q.push(s);dis[s]=1;
while (!q.empty())
{
int k=q.front();
q.pop();
for (int i=first[k];i;i=e[i].next)
if(!dis[e[i].v]&&e[i].w)
q.push(e[i].v),dis[e[i].v]=dis[k]+1;
}
return dis[t];
}
int dfs(int x,int maxn)
{
if (x==t) return maxn;
int used=0;
for (int i=first[x];i;i=e[i].next)
if(dis[e[i].v]==dis[x]+1)
{
int k=dfs(e[i].v,min(maxn-used,e[i].w));
e[i].w-=k;e[i^1].w+=k;
used+=k;
if (used==maxn) return maxn;
}
if (!used) dis[x]=0;
return used;
}
main()
{
int x;
scanf("%d",&T);
while (T--)
{
memset(first,0,sizeof(first));
scanf("%d",&n);
int ans=n;
t=2*n+1;tot=1;
for (int i=1;i<=n;i++)
{
scanf("%d",a+i);
if (a[i])
add(s,i,1),
add(i,s,0);
else add(i+n,t,1),add(t,i+n,0);
}
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
if (a[i])
if (!x) add(i+n,t,1),add(t,i+n,0);
else ans--;
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
scanf("%d",&x);
if (x||i==j) add(i,j+n,1),add(j+n,i,0);
}
while (bfs()) ans-=dfs(s,0x7fffff);
if (ans) puts("T_T");
else puts("^_^");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: