大致思路:
题目是需要求两个“阵营”之间有多少对好朋友,以及改变了意见的人(其实也是处于两个“阵营”的意思)。
求最小割!(最小割:一个无向连通网络,去掉一个边集可以使其变成两个连通分量则这个边集就是割集;最小割集当然就权和最小的割集。)
最小割最大流定理——用dinic求最大流,则其数值=最小割。
注意求最小割的前提是“无向”!所以我们在建图连边的时候都连双向边即可!(即反向边的权值为1而非0)
AC代码:
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 100000
using namespace std;
struct Edge{
int v,c,next;
Edge(int v,int c,int next):v(v),c(c),next(next){}
Edge(){}
};
Edge e[maxn];
int cnt,n,m;
int p[310];
int d[310];
void init(){
memset(p,-1,sizeof(p));
cnt=0;
}
void insert(int u,int v,int c){
e[cnt]=Edge(v,c,p[u]);
p[u]=cnt++;
}
bool bfs(){
memset(d,-1,sizeof(d));
queue<int>q;
d[0]=0;
q.push(0);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=p[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(e[i].c>0&&d[v]==-1){
d[v]=d[u]+1;
q.push(v);
}
}
}
return d[n+1]!=-1;
}
int dfs(int u,int flow){
if(u==n+1)return flow;
int res=0;
for(int i=p[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(e[i].c>0&&d[v]==d[u]+1){
int tmp=dfs(v,min(flow,e[i].c));
e[i].c-=tmp;
flow-=tmp;
e[i^1].c+=tmp;
res+=tmp;
if(flow==0)
break;
}
}
if(res==0)
d[u]=-1;
return res;
}
int main(){
int k,kk;
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&k);
if(!k){
insert(0,i,1);
insert(i,0,1);
}else{
insert(i,n+1,1);
insert(n+1,i,1);
}
}
for(int i=1;i<=m;i++){
scanf("%d%d",&k,&kk);
insert(k,kk,1);
insert(kk,k,1);
}
// printf("%d\n",cnt);
int res=0;
while(bfs()){
// printf("d[n+1]=%d\n",d[n+1]);
res+=dfs(0,0x3f3f3f3f);
}
printf("%d\n",res);
return 0;
}