您的位置:首页 > 其它

【bzoj2768】【JLOI2010】【冠军调查】【最小割】

2016-03-28 17:01 369 查看

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个人他违心说了话。

题解:源点向每个初始立场为1的人连权值为1的边。

         每个初始立场为0的人向汇点连权值为1的边。

         好朋友之间互相连权值为1的边。

        最小割即是答案。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define M 1001001
#define N 310
#define INF 2100000000
using namespace std;
struct use{int st,en,v;}e[M];
int point
,next[M],n,a
,s,cnt(1),x,y;
int cur
,pre
,dis
,gap
,st,en,m;
void add(int x,int y,int v){
next[++cnt]=point[x];point[x]=cnt;e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;
next[++cnt]=point[y];point[y]=cnt;e[cnt].st=y;e[cnt].en=x;e[cnt].v=0;
}
int isap(){
int ans(0),minn,i,u;bool f=false;gap[0]=en-st+1;u=st;
for (int i=st;i<=en;i++) cur[i]=point[i];
while (dis[st]<=en-st+1){
f=false;
for (i=cur[u];i;i=next[i]) if(e[i].v&&dis[u]==dis[e[i].en]+1){cur[u]=i;f=true;break;}
if (f){
u=e[i].en;pre[u]=i;
if (u==en){
minn=INF;
for (int i=en;i!=st;i=e[pre[i]].st)minn=min(minn,e[pre[i]].v);
ans+=minn;
for (int i=en;i!=st;i=e[pre[i]].st)e[pre[i]].v-=minn,e[pre[i]^1].v+=minn;
u=st;
}
}
else{
--gap[dis[u]];if (!gap[dis[u]]) return ans; minn=en-st+1;
for (int i=point[u];i;i=next[i]) if (e[i].v) minn=min(minn,dis[e[i].en]);
dis[u]=minn+1;gap[dis[u]]++;cur[u]=point[u];if (u!=st)u=e[pre[u]].st;
}
}
return ans;
}
int main(){
scanf("%d%d",&n,&m);st=1;en=n+2;
for (int i=1;i<=n;i++){
scanf("%d",&x);
if (x==1) add(st,i+1,1);
else add(i+1,en,1);
}
for (int i=1;i<=m;i++){scanf("%d%d",&x,&y);add(x+1,y+1,1);add(y+1,x+1,1);}
printf("%d\n",isap());
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: