大致思路:
题目是需要求两个“阵营”之间有多少对好朋友,以及改变了意见的人(其实也是处于两个“阵营”的意思)。
求最小割!(最小割:一个无向连通网络,去掉一个边集可以使其变成两个连通分量则这个边集就是割集;最小割集当然就权和最小的割集。)
最小割最大流定理——用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; }