洛谷 2057_善意的投票_网络流

发布于 2019-05-18  9 次阅读


题目描述

幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉。对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神。虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票。我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所有和自己本来意愿发生冲突的人数。

我们的问题就是,每位小朋友应该怎样投票,才能使冲突数最小?


思路

将投同意的和源点0连边,将不同意的和汇点n+1连边
对于每一个好朋友都连一个双向边
跑最大流就可以了


#include 
#include 
#include 
#define maxn 400000
#define min(x,y) x'9'){if (ch=='-')p=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*p;
}
int add(int x,int y,int w)
{
    e[++maxE]=(edge){y,w,ls[x]};
    ls[x]=maxE;
    e[++maxE]=(edge){x,0,ls[y]};
    ls[y]=maxE;
}
int bfs(int x)
{
    queue  t;
    t.push(x);
    fill(state,0);
    state[x]=1;
    while (!t.empty())
    {
        int tt=t.front();t.pop();
        for (int i=ls[tt];i;i=e[i].next)
        {
            if (e[i].w>0&&!state[e[i].y])
            {
                state[e[i].y]=state[tt]+1;
                t.push(e[i].y);
                if (e[i].y==E)
                    return true;
            }
        }
    }
    return false;
}
int find(int x,int mn)
{
    if (x==E||!mn) return mn;
    int ret=0;
    for (int i=ls[x];i;i=e[i].next)
        if (state[x]+1==state[e[i].y]&&e[i].w>0)
        {
            int d=find(e[i].y,min(mn-ret,e[i].w));
            e[i].w-=d;
            e[i^1].w+=d;
            ret+=d;
            if (ret==mn) break;
        }
    return ret;
}
int main()
{
    int n=read(),m=read();
    S=0;E=n+1;
    for (int i=1;i<=n;i++)
    {
        int x=read();
        if (x==1) add(S,i,1);
        else add(i,E,1);
    }
    for (int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        add(x,y,1);
        add(y,x,1);
    }
    int ans=0;
    while (bfs(S))
        ans+=find(S,INF);
    printf("%d\n",ans);
}
]]>