[BZOJ1934/Luogu2057][SHOI2007]Vote 善意的投票 题解

题目链接:

BZOJ1934

Luogu2057

首先,看到求最小冲突以及这\(n\le 300\)的数据范围,很容易联想到最小割。

如何建图?

首先把人分成两份,意见为\(1\)的与源点连边,容量为\(1\),否则与汇点连边,容量也设为\(1\),表示更改自己意见的代价。

接着对每一对朋友之间连一条双向边,容量为\(1\),表示朋友之间的冲突。

最后求一遍最小割(最大流)即可。

这里用的\(Dinic\),时间复杂度\(O(n^3)\)

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>

int n,m,St,Ed;
int Head[305],Next[200005],To[200005],Val[200005],En=1;
int Dep[305];

inline void Add(int x,int y)
{
    Next[++En]=Head[x],To[Head[x]=En]=y,Val[En]=1;
    Next[++En]=Head[y],To[Head[y]=En]=x,Val[En]=0;
}

bool BFS()
{
    std::queue<int> q;
    memset(Dep,0,sizeof Dep);
    Dep[St]=1,q.push(St);
    while(!q.empty())
    {
        int x=q.front(),y;
        q.pop();
        for(int i=Head[x];i;i=Next[i])
            if(Val[i]&&!Dep[y=To[i]])
            {
                Dep[y]=Dep[x]+1;
                if(y==Ed)return true;
                q.push(y);
            }
    }
    return false;
}

int Dinic(int x,int Flow)
{
    if(x==Ed)return Flow;
    int k,Rest=Flow,y;
    for(int i=Head[x];i&&Rest;i=Next[i])
        if(Val[i]&&Dep[y=To[i]]==Dep[x]+1)
        {
            k=Dinic(y,std::min(Rest,Val[i]));
            if(!k)Dep[y]=0;
            Val[i]-=k,Val[i^1]+=k,Rest-=k;
        }
    return Flow-Rest;
}

int main()
{
    scanf("%d%d",&n,&m);
    St=n+1,Ed=n+2;
    for(int i=1,Sup;i<=n;++i)
    {
        scanf("%d",&Sup);
        if(Sup)Add(St,i);
        else Add(i,Ed);
    }
    for(int x,y;m--;)
    {
        scanf("%d%d",&x,&y);
        Add(x,y),Add(y,x);
    }
    int Maxf=0,Fs;
    while(BFS())
        while((Fs=Dinic(St,1<<30)))
            Maxf+=Fs;
    printf("%d\n",Maxf);
    return 0;
}

转载于:https://www.cnblogs.com/LanrTabe/p/10143402.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值