最小割,考虑最小割就是要将整张图分为两块,本题中就分别表示赞同和不赞同,那么首先一开始赞同的点向S连边,不赞同的点向T连边,如果这些点分到了另一边就要割掉这条边,朋友关系同理,连双向边同样表示分到两边要割掉这条边,跑最小割=最大流即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 305
 4 struct ji{
 5     int nex,to,len;
 6 }edge[N*N];
 7 queue<int>q;
 8 int E,n,m,x,y,head[N],work[N],d[N];
 9 void add(int x,int y,int z){
10     edge[E].nex=head[x];
11     edge[E].to=y;
12     edge[E].len=z;
13     head[x]=E++;
14     if (E&1)add(y,x,0);
15 }
16 bool bfs(){
17     memset(d,-1,sizeof(d));
18     q.push(0);
19     d[0]=0;
20     while (!q.empty()){
21         int k=q.front();
22         q.pop();
23         for(int i=head[k];i!=-1;i=edge[i].nex)
24             if ((edge[i].len)&&(d[edge[i].to]<0)){
25                 d[edge[i].to]=d[k]+1;
26                 q.push(edge[i].to);
27             }
28     }
29     return d[n+1]>=0;
30 }
31 int dfs(int k,int s){
32     if (k>n)return s;
33     int p;
34     for(int &i=work[k];i!=-1;i=edge[i].nex)
35         if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){
36             p=dfs(edge[i].to,min(s,edge[i].len));
37             if (p){
38                 edge[i].len-=p;
39                 edge[i^1].len+=p;
40                 return p;
41             }
42         }
43     return 0;
44 }
45 int main(){
46     scanf("%d%d",&n,&m);
47     memset(head,-1,sizeof(head));
48     for(int i=1;i<=n;i++){
49         scanf("%d",&x);
50         if (x)add(0,i,1);
51         else add(i,n+1,1);
52     }
53     for(int i=1;i<=m;i++){
54         scanf("%d%d",&x,&y);
55         add(x,y,1);
56         edge[E-1].len=1;
57     }
58     int ans=0;
59     while (bfs()){
60         memcpy(work,head,sizeof(head));
61         while (x=dfs(0,0x3f3f3f3f))ans+=x;
62     }
63     printf("%d",ans);
64 } 
View Code
01-03 02:35