bzoj1934: [Shoi2007]Vote 善意的投票
一定要想到是最小割。
虚拟源点S连支持者容量为1,反对者连虚拟汇点容量为1,支持者连反对者容量为1。
割俩面的点,一面是支持,一面是反对,冲突数就是割(哥。。雾)。
最小冲突数就是最小割。
#include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int maxn = 300 + 10; const int maxm = 100000 + 10; const int INF = 0x3f3f3f3f; int g[maxn],v[maxm],next[maxm],f[maxm],eid=0; int n,m,a[maxn],S,T; int d[maxn],gap[maxn]; void addedge(int a,int b,int F) { v[eid]=b; next[eid]=g[a]; f[eid]=F; g[a]=eid++; v[eid]=a; next[eid]=g[b]; f[eid]=0; g[b]=eid++; } int ISAP(int u,int flow) { if(u==T) return flow; int aug,cur=0,mindist=n; for(int i=g[u];~i;i=next[i]) if(d[u]==d[v[i]]+1 && f[i]>0) { aug=ISAP(v[i],min(f[i],flow-cur)); f[i]-=aug; f[i^1]+=aug; cur+=aug; if(cur==flow || d[S] == n) return cur; } if(cur==0) { if(!--gap[d[u]]) { d[S] = n; return cur; } for(int i=g[u];~i;i=next[i]) if(f[i]) mindist=min(mindist,d[v[i]]); ++gap[d[u]=mindist+1]; } return cur; } void solve() { gap[0]=n; int res=0; while(d[S]<n) res+=ISAP(S,INF); printf("%d\n",res); } int main() { scanf("%d%d",&n,&m); S=n+1; T=n+2; memset(g,-1,sizeof(g)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i]==1) addedge(S,i,1); else addedge(i,T,1); } n=n+2; for(int i=1,u,v;i<=m;i++) { scanf("%d%d",&u,&v); if(a[u]!=a[v]) { if(a[u]==1) addedge(u,v,1); else addedge(v,u,1); } } solve(); return 0; }