【BZOJ2768】冠军调查,网络流之最小割

Time:2016.07.19
Author:xiaoyimi
转载注明出处谢谢


传送门
思路:
按照赞成与反对组成二分图
分别向s,t连边,流量为1
意见不同的朋友连边,流量为1
跑出的最大流即为答案
举例说明——若a,b是好朋友,a支持b反对,那么要么让a违心,割掉s->a的边,要么让b违心,割掉b->t的边,要么a,b相反,割掉a->b
注意:无
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
int n,m,tot=1,s,t;
int first[305],dis[305];
bool F[305];
struct edge{
    int u,v,w,next;
}e[50000];
int in()
{
    int t=0;char ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    while (isdigit(ch)) t=(t<<1)+(t<<3)+ch-48,ch=getchar();
    return t;
}
void add(int x,int y,int z)
{
    e[++tot]=(edge){x,y,z,first[x]};
    first[x]=tot;
    e[++tot]=(edge){y,x,0,first[y]};
    first[y]=tot;
}
bool bfs()
{
    queue<int>q;
    memset(dis,0,sizeof(dis));
    dis[s]=1;
    q.push(s);
    for (int k;!q.empty();q.pop())
    {
        k=q.front();
        for (int i=first[k];i;i=e[i].next)
            if (!dis[e[i].v]&&e[i].w)
                dis[e[i].v]=dis[k]+1,
                q.push(e[i].v);
    }
    return dis[t];
}
int dfs(int x,int mx)
{
    if (x==t) return mx;
    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(e[i].w,mx-used));
        e[i].w-=k;e[i^1].w+=k;
        used+=k;
        if (used==mx) return used;
    }
    if (!used) dis[x]=0;
    return used;
}
main()
{
    n=in();m=in();
    t=n+1;
    for (int i=1;i<=n;i++)
    {
        F[i]=in();
        if (F[i]) add(s,i,1);
        else add(i,t,1);
    }
    int x,y;
    for (int i=1;i<=m;i++)
    {
        x=in();y=in();
        if (F[x]^F[y])
        {
            if (F[x]) add(x,y,1);
            else add(y,x,1);
        }
    }
    int ans=0;
    while (bfs()) ans+=dfs(s,0x7fff);
    printf("%d",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值