ACM-ICPC 2018 瀋陽賽區網路預賽
阿新 • • 發佈:2018-12-09
題意:
給出一張二分圖,初始每個節點的度數都為零。選擇若干條邊,使得每個節點的度數範圍再[L,R]範圍內。每選一條邊,邊上兩端的節點度數+1。
做法:
這道題就是:建一個虛擬源點和一個虛擬匯點,虛擬源點到左邊每個點連一條流量為R-L的邊,右邊每個點到虛擬匯點連一條流量為R-L的邊。中間二分圖的每條邊流量當然為1,由匯點向源點連一條流量無限大的邊。之後再建一個超級源點和一個超級匯點,由超級源點向左邊每個點連一條流量為L的邊,由右邊每個點向超級匯點連一條流量為L的邊。跑一遍最大流,如果超級源點和超級匯點所連的邊跑滿(因為一定相等),則存在可行解,否則不存在。
#include<bits/stdc++.h> using namespace std; const int Ni = 40005; const int MAX = 1<<26; struct Edge{ int u,v,c; int next; }edge[3*Ni]; int n,m,cnt,head[Ni],d[Ni],sp,tp,heads[Ni];//原點,匯點 int l,r; void add(int u,int v,int c){ edge[cnt].u=u; edge[cnt].v=v; edge[cnt].c=c; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].u=v; edge[cnt].v=u; edge[cnt].c=0; edge[cnt].next=head[v]; head[v]=cnt++; } int bfs(){ queue <int> q; memset(d,-1,sizeof(d)); d[sp]=0; q.push(sp); while(!q.empty()){ int cur=q.front(); q.pop(); for(int i=head[cur];i!=-1;i=edge[i].next){ int u=edge[i].v; if(d[u]==-1 && edge[i].c>0){ d[u]=d[cur]+1; q.push(u); } } } return d[tp] != -1; } int dfs(int a,int b){ int r=0; if(a==tp)return b; for(int i=heads[a];i!=-1 && r<b;i=edge[i].next) { int u=edge[i].v; if(edge[i].c>0 && d[u]==d[a]+1) { int x=min(edge[i].c,b-r); heads[a]=i; x=dfs(u,x); r+=x; edge[i].c-=x; edge[i^1].c+=x; } } if(!r)d[a]=-2; return r; } int dinic(int sp,int tp){ int total=0,t; while(bfs()){ memcpy(heads,head,sizeof(head)); while(t=dfs(sp,MAX)) total+=t; } return total; } int main(){ int i,u,v,k,cas=0; while(~scanf("%d%d%d",&n,&m,&k)){ scanf("%d%d",&l,&r); cnt=0; memset(heads,-1,sizeof(heads)); memset(head,-1,sizeof(head)); sp=n+m+1,tp=n+m+2; //附加源,附加匯 int s=n+m+3,t=n+m+4; for(int i=1;i<=k;i++){ scanf("%d%d",&u,&v); add(u,v+n,1); } for(int i=1;i<=n;i++){ add(s,i,r-l); //源點連向所有左側點,修改流量為R-L add(sp,i,l); //附加源連向所有左側點,流量為L,表示必要弧 add(s,tp,l); //源點連向附加匯 } for(int i=1;i<=m;i++){ int aim=i+n; add(aim,t,r-l); //右側點連向匯點,修改流量為R-L add(aim,tp,l); //附加源連向匯點 add(sp,t,l); //右側點連向附加匯,流量為L,表示必要弧 } add(t,s,MAX); printf("Case %d: ",++cas); int ans=dinic(sp,tp); //求附加源到附加匯的最大流,若滿足 if(ans==(n+m)*l) printf("Yes\n");//附加源到附加匯的所有弧都滿流,則有可行流 else printf("No\n"); } return 0; }