【BZOJ-2768】冠军调查 最小割

2768: [JLOI2010]冠军调查

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 971  Solved: 661
[Submit][Status][Discuss]

Description

一年一度的欧洲足球冠军联赛已经进入了淘汰赛阶段。随着卫冕冠军巴萨罗那的淘汰,英超劲旅切尔西成为了头号热门。新浪体育最近在吉林教育学院进行了一次大规模的调查,调查的内容就是关于切尔西能否在今年问鼎欧洲冠军。新浪体育的记者从各个院系中一共抽取了n位同学作为参与者,大家齐聚一堂,各抒己见。每一位参与者都将发言,阐述自己的看法。参与者的心里都有一个看法,比如FireDancer认为切尔西不可能夺冠,而WaterDancer认为切尔西一定问鼎。但是因为WaterDancer是FireDancer的好朋友,所以可能FireDancer为了迁就自己的好朋友,会在发言中支持切尔西。也就是说每个参与者发言时阐述的看法不一定就是心里所想的。现在告诉你大家心里的想法和参与者的朋友网,希望你能安排每个人的发言内容,使得违心说话的人的总数与发言时立场不同的朋友(对)的总数的和最小。
 

Input

第一行两个整数n和m,其中n(2≤n≤300)表示参与者的总数,m(0≤m≤n(n-1)/2)表示朋友的总对数。
第二行n个整数,要么是0要么是1。如果第i个整数的值是0的话,表示第i个人心里认为切尔西将与冠军无缘,如果是1的话,表示他心里认为切尔西必将夺魁。
下面m行每行两个不同的整数,i和j(1≤i, j≤n)表示i和j是朋友。注意没有一对朋友会在输入中重复出现。朋友关系是双向的,并且不会传递。
 

Output

 
只有一个整数,为最小的和。

Sample Input

3 3
1 0 0
1 2
1 3
2 3

Sample Output

1

HINT

 

最好的安排是所有人都在发言时说切尔西不会夺冠。这样没有一对朋友的立场相左,只有第1个人他违心说了话。

 

Source

Solution

比较简单的最小割

设S集合为支持集,T集合为不支持集

对于所有支持的人,被S连;所有不支持的人,向T连

朋友之间互相连

容量全部为1

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
#define MAXN 1010
#define MAXM 1000010
struct EdgeNode{int next,to,cap;}edge[MAXM];
int head[MAXN],cnt=1,S,T;
void add(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w;}
void insert(int u,int v,int w) {add(u,v,w); add(v,u,0);} 
int N,M;
int cur[MAXN],h[MAXN];
#define inf 0x7fffffff
bool bfs()
{
    queue<int>q;
    for (int i=S; i<=T; i++) h[i]=-1;
    h[S]=1; q.push(S);
    while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (int i=head[now]; i; i=edge[i].next)
                if (h[edge[i].to]==-1 && edge[i].cap)
                    h[edge[i].to]=h[now]+1,q.push(edge[i].to);
        }
    return h[T]!=-1;        
}
int dfs(int loc,int low)
{
    if (loc==T) return low;
    int used=0,w;
    for (int i=cur[loc]; i; i=edge[i].next)
        if (edge[i].cap && h[edge[i].to]==h[loc]+1)
            {
                w=dfs(edge[i].to,min(edge[i].cap,low-used));
                edge[i].cap-=w; edge[i^1].cap+=w; used+=w;
                if (used==low) return low;
                if (edge[i].to) cur[loc]=i;
            }
    if (!used) h[loc]=-1;
    return used;
}
int dinic()
{
    int tmp=0;
    while (bfs())
        {
            for (int i=S; i<=T; i++) cur[i]=head[i];
            tmp+=dfs(S,inf);
        }
    return tmp;
}
int main()
{
    N=read(); M=read();
    S=0,T=N+1;
    for (int x,i=1; i<=N; i++)
         {
             x=read();
             if (x) insert(S,i,1);
             else insert(i,T,1);
         }
    for (int x,y,i=1; i<=M; i++)
        {
            x=read(),y=read();
            insert(x,y,1); insert(y,x,1);
        }
    printf("%d\n",dinic());
    return 0;
}

 

posted @ 2016-07-17 17:07  DaD3zZ  阅读(213)  评论(0编辑  收藏  举报