BZOJ 1934: [Shoi2007]Vote 善意的投票

BZOJ 1934: [Shoi2007]Vote 善意的投票

标签(空格分隔): OI-BZOJ OI-最小割

Time Limit: 1 Sec
Memory Limit: 64 MB

Description

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

第一行只有两个整数n,m,保证有2≤n≤300,1≤m≤n(n-1)/2。其中n代表总人数,m代表好朋友的对数。文件第二行有n个整数,第i个整数代表第i个小朋友的意愿,当它为1时表示同意睡觉,当它为0时表示反对睡觉。接下来文件还有m行,每行有两个整数i,j。表示i,j是一对好朋友,我们保证任何两对i,j不会重复。
Output

只需要输出一个整数,即可能的最小冲突数。
Sample Input

3 3

1 0 0

1 2

1 3

3 2

Sample Output

1
HINT

在第一个例子中,所有小朋友都投赞成票就能得到最优解

Solution

最小割,i睡觉S就向i连容量为1的边,否则i向T连容量为1的边,若2个人是好朋友,就在2人间连容量为1的无向边,跑一边最小割=最大流

Code

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
int read()
{
    int s=0,f=1;char ch=getchar();
    while(!('0'<=ch&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
int S,T,n,m,np;
int A[305];
int be[100005],bn[200005],bv[200005],bl[200005],bw=1;
void put(int u,int v,int l)
{bw++;bn[bw]=be[u];be[u]=bw;bv[bw]=v;bl[bw]=l;}
int d[100005];
bool spfa(int S,int T)
{
    for(int i=1;i<=np;i++)
       d[i]=10000000;
    d[S]=1;
    queue<int>q;
    for(q.push(S);!q.empty();)
       {int u=q.front();q.pop();
        for(int i=be[u],v;i;i=bn[i])
           if(d[v=bv[i]]>d[u]+1&&bl[i])
             {d[v]=d[u]+1;
              q.push(v);
             }
       }
    return d[T]!=10000000;
}
int ans;
int dinic(int u,int mf,int T)
{
    if(mf==0)return 0;
    if(u==T)return mf;
    int sum=0;
    for(int i=be[u],v;i;i=bn[i])
       if(d[v=bv[i]]==d[u]+1)
         {int f=dinic(v,min(mf-sum,bl[i]),T);
          bl[i]-=f;
          bl[i^1]+=f;
          sum+=f;
         }
    return sum;
}
int main()
{
    n=read();m=read();
    S=++np,T=++np;
    for(int i=1;i<=n;i++)
       {A[i]=++np;
        if(read())
          put(S,A[i],1),
          put(A[i],S,0);
        else
          put(A[i],T,1),
          put(T,A[i],0);
       }
    for(int i=1;i<=m;i++)
       {int u=read(),v=read();
        put(A[u],A[v],1),
        put(A[v],A[u],1);
       }
    while(spfa(S,T))ans+=dinic(S,1e9,T);
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(BZOJ 1934: [Shoi2007]Vote 善意的投票)