1. 程式人生 > >洛谷 P2057 善意的投票(網絡流最小割)

洛谷 P2057 善意的投票(網絡流最小割)

ont c++ emp else 題意 art 自己 www. pop

P2057 善意的投票

題目描述

幼兒園裏有n個小朋友打算通過投票來決定睡不睡午覺。對他們來說,這個問題並不是很重要,於是他們決定發揚謙讓精神。雖然每個人都有自己的主見,但是為了照顧一下自己朋友的想法,他們也可以投和自己本來意願相反的票。我們定義一次投票的沖突數為好朋友之間發生沖突的總數加上和所有和自己本來意願發生沖突的人數。

我們的問題就是,每位小朋友應該怎樣投票,才能使沖突數最小?

輸入輸出格式

輸入格式:

文件的第一行只有兩個整數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不會重復。

輸出格式:

只需要輸出一個整數,即可能的最小沖突數。

輸入輸出樣例

輸入樣例#1:
3 3
1 0 0
1 2
1 3
3 2
輸出樣例#1:
1

說明

2≤n≤300,1≤m≤n(n-1)/2。

Solution:

  題意大致就是有n個人有兩種不同的意見並且有許多朋友,需要讓朋友間盡可能的統一意見(少發生沖突),如果一個人違反自己的本意也算沖突,求最少的沖突。。。明眼人直接發現是最小割,兩種意見可以看作源點S和T,我們需要做的是割最少的邊使得S和T成為兩個不同的集合,解釋:割掉的邊相當於1次沖突(因為若某邊被割走,則顯然這條邊相連的兩個點分別通向了S和T,所以算是一次沖突),當S和T還連通時則必然存在一條路徑,這樣肯定會有沖突,所以需要使得S和T孤立。

  實現時這樣建圖:直接將S連向同意的人,T連向不同意的人,若兩人是朋友,則在他們之間連一條雙向邊(這裏有些人不理解,若兩個人有沖突,則只需要其中任意一個人改變意見就行了,簡單說可能是a同意b的意見或者b同意a的意見,只需割掉一條邊,但是有兩種情況,所以建雙向邊)。

  最後就是求最小割了,直接套上最大流的模板就ok了。

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 using namespace std;
 4 const int N=100005,inf=23333333;
 5 int n,m,s,t=520
,h[N],cnt=1,dis[N],ans; 6 struct edge{ 7 int to,net,v; 8 }e[N*4]; 9 il void add(int u,int v,int w) 10 { 11 e[++cnt].to=v,e[cnt].net=h[u],e[cnt].v=w,h[u]=cnt; 12 e[++cnt].to=u,e[cnt].net=h[v],e[cnt].v=0,h[v]=cnt; 13 } 14 queue<int>q; 15 il bool bfs() 16 { 17 memset(dis,-1,sizeof(dis)); 18 q.push(s),dis[s]=0; 19 while(!q.empty()) 20 { 21 int u=q.front();q.pop(); 22 for(int i=h[u];i;i=e[i].net) 23 if(dis[e[i].to]==-1&&e[i].v>0)dis[e[i].to]=dis[u]+1,q.push(e[i].to); 24 } 25 return dis[t]!=-1; 26 } 27 il int dfs(int u,int op) 28 { 29 if(u==t)return op; 30 int flow=0,used=0; 31 for(int i=h[u];i;i=e[i].net) 32 { 33 int v=e[i].to; 34 if(dis[v]==dis[u]+1&&e[i].v>0) 35 { 36 used=dfs(v,min(op,e[i].v)); 37 if(!used)continue; 38 flow+=used,op-=used; 39 e[i].v-=used,e[i^1].v+=used; 40 if(!op)break; 41 } 42 } 43 if(!op)dis[u]=-1; 44 return flow; 45 } 46 int main() 47 { 48 scanf("%d%d",&n,&m); 49 int x,y; 50 for(int i=1;i<=n;i++){ 51 scanf("%d",&x); 52 if(x==1)add(s,i,1); 53 else add(i,t,1); 54 } 55 for(int i=1;i<=m;i++){ 56 scanf("%d%d",&x,&y); 57 add(x,y,1),add(y,x,1); 58 } 59 while(bfs())ans+=dfs(s,inf); 60 cout<<ans; 61 return 0; 62 }

洛谷 P2057 善意的投票(網絡流最小割)