【Luogu】P2057善意的投票(最小割转最大流)
也算水题一道吧,不过Round1感性理解一下就xjb建了个图,40
Round2仔细分析了一会,理性建了个图,90
然后分析了半天……改大数组就A了……
从S到所有值为1的点连一条inf的边,从所有值为0的点向T连一条inf的边
然后对于每个值为1的点分析:
把点拆成A部和B部
改立场后自我谴责,从A部向B部连一条
改立场后本来同立场的朋友谴责,从$x_{A}$向$y_{B}$连一条
然后本来立场就不一样的朋友相信大家都会搞
然后最小割转最大流,dinic跑一下就A了
其实这题貌似不能算水题……?我也想了将近一个小时的细节……
只不过最后能被我想出来的都是水题,这个我非常确定qwq
(因为我太水了)
#include<cstdio> #include<cstdlib> #include<cctype> #include<cstring> #include<algorithm> #include<queue> #define maxn 5000 #define maxm 200010 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } struct Edge{ int next,to,val; }edge[maxm]; int head[maxn],num; inline void addedge(int from,int to,int val){ edge[++num]=(Edge){head[from],to,val}; head[from]=num; } inline void add(int from,int to,int val){ addedge(from,to,val); addedge(to,from,0); } inline int count(int i){ return i&1?i+1:i-1; } bool vis[maxn]; int dfn[maxn]; int list[maxn]; int Start,End; bool bfs(){ memset(vis,0,sizeof(vis)); queue<int>q; q.push(Start); dfn[Start]=vis[Start]=1; while(!q.empty()){ int from=q.front(); q.pop(); for(int i=head[from];i;i=edge[i].next){ int to=edge[i].to; if(vis[to]||edge[i].val==0) continue; vis[to]=1; q.push(to); dfn[to]=dfn[from]+1; } } return vis[End]; } int dfs(int x,int val){ //printf("%d %d\n",x,val); if(x==End||val==0) return val; int flow=0; vis[x]=1; for(int i=list[x];i;i=edge[i].next){ int to=edge[i].to; if(vis[to]||edge[i].val==0||dfn[to]!=dfn[x]+1) continue; int now=dfs(to,min(val,edge[i].val)); flow+=now; edge[i].val-=now; edge[count(i)].val+=now; val-=now; if(val<=0) break; } if(flow!=val) dfn[x]=-1; return flow; } int maxflow(){ int ans=0; while(bfs()){ memset(vis,0,sizeof(vis)); for(int i=Start;i<=End;++i) list[i]=head[i]; int now=dfs(Start,10000000); if(now==0) break; ans+=now; } return ans; } int q[maxn]; int qa[maxn],qb[maxn]; int n,m; int main(){ n=read(),m=read();End=maxn-10; for(int i=1;i<=n;++i) q[i]=read(); for(int i=1;i<=m;++i){ qa[i]=read();qb[i]=read(); } for(int i=1;i<=n;++i){ if(q[i]==1){ add(Start,i,0x7fffffff); add(i,i+n,1); //拆点 add(i+n,i+n*2,1); //谴责自己 } else{ add(i+n*5,End,0x7fffffff); add(i+n*4,i+n*5,1); //拆点 add(i+n*3,i+n*4,1); //谴责自己 } } for(int i=1;i<=m;++i){ int x=qa[i],y=qb[i]; if(q[x]<q[y]) swap(x,y); if(q[x]==1&&q[y]==1){ add(x+n,y+n*2,1); //互相谴责qwq add(y+n,x+n*2,1); } else if(q[x]==1&&q[y]==0) add(x+n*2,y+n*3,1); else{ add(x+n*3,y+n*4,1); add(y+n*3,x+n*4,1); } } printf("%d",maxflow()); return 0; } /* 5 5 1 0 0 1 0 1 4 1 3 2 4 3 5 4 5 6 7 1 0 1 1 0 1 1 3 1 2 1 4 3 5 3 6 4 6 4 5 */