C++之路进阶——最大流(善意的投票)

F.A.Qs Home Discuss ProblemSet Status Ranklist Contest ModifyUser   hyxzc Logout 捐赠本站
Notice:由于本OJ建立在Linux平台下,而许多题的数据在Windows下制作,请注意输入、输出语句及数据类型及范围,避免无谓的RE出现。

1934: [Shoi2007]Vote 善意的投票

Time Limit: 1 Sec  Memory Limit: 64 MB
Submit: 1646  Solved: 1006
[Submit][Status][Discuss]

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

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

题解:

    将点与S、T点分别连边,权值为1或0,将路径连边,最大流

代码:

  

 1 #include<cstdio>
 2 #include<queue>
 3 #include<cstring>
 4 #define maxn 310
 5 #include<iostream>
 6   
 7 using namespace std;
 8   
 9 int S=0,T,head[maxn],dis[maxn],maxlow,ans,cnt=1,n,m,x[maxn];
10 struct ss
11    {
12     int to;
13     int next;
14     int edge;
15    }e[130100];
16   
17 void add(int u,int v,int w)
18     {
19         e[++cnt].next=head[u];
20         head[u]=cnt;
21         e[cnt].to=v;
22         e[cnt].edge=w;
23     }
24   
25 void insert(int u,int v,int w)
26     {
27         add(u,v,w);
28         add(v,u,0);
29     } 
30      
31 bool bfs()
32     {
33         for (int i=1;i<=T;i++) dis[i]=0x7fffffff;
34         queue<int>que;
35         que.push(S);
36         dis[0]=0;
37         while (!que.empty())
38            {
39              int now=que.front();
40              que.pop();
41              for (int i=head[now];i;i=e[i].next)
42                if (e[i].edge&&dis[e[i].to]>dis[now]+1)
43                 {
44                    dis[e[i].to]=dis[now]+1;
45                    que.push(e[i].to);
46                    if (e[i].to==T)  return 1;    
47                 }
48            }
49       return 0;    
50     }     
51   
52 int dinic(int x,int inf)
53     {
54       if (x==T) return inf; 
55       int rest=inf;
56       for (int i=head[x];i&&rest;i=e[i].next)
57         if (e[i].edge&&dis[e[i].to]==dis[x]+1) 
58          {
59             int now=dinic(e[i].to,min(rest,e[i].edge));
60             if (!now) dis[now]=0;
61             e[i].edge-=now;
62             e[i^1].edge+=now;
63             rest-=now;
64          }  
65      return inf-rest;    
66     }
67   
68 int main()
69    {
70      scanf("%d%d",&n,&m);
71      T=n+1;
72      for (int i=1;i<=n;i++)
73        {
74           int x;
75           scanf("%d",&x);
76           if (x)
77                insert(0,i,1),insert(i,T,0);
78               else
79                insert(i,T,1),insert(0,i,0);     
80        }
81      for (int i=1;i<=m;i++)
82         {
83            int u,v;
84            scanf("%d%d",&u,&v);
85            insert(u,v,1);
86            insert(v,u,1);   
87         } 
88     while (bfs()) 
89        while (ans=dinic(S,0x7fffffff)) maxlow+=ans;
90     printf("%d\n",maxlow);   
91     return 0;
92    }

 

你可能感兴趣的:(C++之路进阶——最大流(善意的投票))