P2057 [SHOI2007] 善意的投票 / [JLOI2010] 冠军调查
P2057 [SHOI2007] 善意的投票 / [JLOI2010] 冠军调查
看到数据范围一眼网络流:
对于每个人,将其拆成两个点
我们对
然后对于他的朋友,直接交叉连边
然后最后把答案减掉
Code:
#include<bits/stdc++.h> const int N=605; const int inf=1e9; using namespace std; int n,m,e_cnt=1,S,T,ans; struct Edge{ int to,nxt,flow; }e[N*N*2]; int head[N]; void add(int x,int y,int fl) { e[++e_cnt]=Edge{y,head[x],fl}; head[x]=e_cnt; e[++e_cnt]=Edge{x,head[y],0}; head[y]=e_cnt; } queue<int> Q; int dl[N],dis[N],flow[N],pre[N]; void init() { for(int i=S;i<=T;i++)dis[i]=inf,flow[i]=0; } bool spfa(int s,int t) { init(); Q.push(s); dis[s]=0;flow[s]=inf; while(!Q.empty()) { int u=Q.front();Q.pop(); dl[u]=0; //cout<<u<<":\n"; for(int i=head[u];i;i=e[i].nxt) { int v=e[i].to,fl=e[i].flow; //cout<<v<<" "<<"="<<dis[v]<<" "<<dis[u]+1<<" "<<fl<<"\n"; if(dis[v]>dis[u]+1&&fl) { flow[v]=min(fl,flow[u]); dis[v]=dis[u]+1; pre[v]=i; if(!dl[v]) { Q.push(v); dl[v]=1; } } } //cout<<"\n"; } //cout<<flow[t]<<"\n"; return flow[t]; } void dinic() { while(spfa(S,T)) { int now=T; ans+=flow[T]; while(now) { //cout<<"now:"<<now<<"\n"; int i=pre[now]; e[i].flow-=flow[T];e[i^1].flow+=flow[T]; now=e[i^1].to; } } } void work() { cin>>n>>m; S=0,T=n+n+1; for(int i=1,opt;i<=n;i++) { scanf("%d",&opt); if(opt==0) { add(S,i,2); add(i+n,T,1); } else { add(S,i,1); add(i+n,T,2); } add(i,i+n,inf); } for(int i=1,x,y;i<=m;i++) { scanf("%d%d",&x,&y); add(x,y+n,1); add(y,x+n,1); } dinic(); printf("%d",ans-n); } int main() { //freopen("vote.in","r",stdin); //freopen("vote.out","w",stdout); work(); return 0; }