http://acm.fzu.edu.cn/problem.php?pid=2274
二分差值,求出最小的存在上下界可行流的答案,再跑一次上下界最小流。
这题恶心的地方在于建图从班级流向寝室会TLE,从寝室流向班级就会快很多。
因为只有三层边,dinic里增广次数只有几次,每次dinic复杂度几乎是O(n+m)的。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=200005,INF=0x3f3f3f3f; const int mxN=200005,mxM=500005; int n,m,k; int du[N]; int ra[N],rb[N],rc[N],rd[N]; int in[N]; int S,T,SS,TT; int inflow; struct graph { int S,T; int base[mxN],vec[2*mxM],pre[2*mxM],tot; int c[2*mxM]; int d[mxN],q[mxN]; bool vis[mxN]; void init() { memset(base,0,sizeof(base)); tot=1; } void link(int x,int y,int z) { vec[++tot]=y; pre[tot]=base[x]; base[x]=tot; c[tot]=z; vec[++tot]=x; pre[tot]=base[y]; base[y]=tot; c[tot]=0; } bool bfs() { int head=0,tail=0; memset(d,-1,sizeof(d)); d[S]=0; q[++tail]=S; while(head<tail) { head++; int u=q[head]; for (int now=base[u];now;now=pre[now]) { int v=vec[now]; if (d[v]==-1&&c[now]>0) { d[v]=d[u]+1; q[++tail]=v; if (v==T) return 1; } } } return 0; } int dfs(int u,int flow) { int r=0; if (u==T) return flow; for (int now=base[u];now&&r<flow;now=pre[now]) { int v=vec[now]; if (c[now]>0&&d[v]==d[u]+1) { int x=min(c[now],flow-r); x=dfs(v,x); r+=x; c[now]-=x; c[now^1]+=x; } } if (!r)d[u]=-2; return r; } int dinic() { int ans=0; while(bfs()) ans+=dfs(S,INF); return ans; } }G; bool pwork(int dif) { G.init(); memset(in,0,sizeof(in)); for (int i=1;i<=k;i++) G.link(n+rd[i],rc[i],1); S=0,T=n+m+3; SS=T-2; TT=T-1; for (int i=1;i<=n;i++) { int l=(du[i]-dif+1)/2; int r=(du[i]+dif)/2; if (l<0) l=0; if (r>du[i]) r=du[i]; if (l>r) return 0; G.link(i,TT,r-l); in[i]-=l; in[TT]+=l; } for (int i=1;i<=m;i++) { int l=du[n+i]-rb[i]; int r=ra[i]; if (r>du[n+i]) r=du[n+i]; if (l<0) l=0; G.link(SS,n+i,r-l); in[SS]-=l; in[n+i]+=l; } inflow=0; for (int i=1;i<T;i++) { if (in[i]>0) G.link(S,i,in[i]),inflow+=in[i]; if (in[i]<0) G.link(i,T,-in[i]); } return 1; } int maxflow; bool check(int dif) { if (!pwork(dif)) return 0; G.S=S; G.T=T; G.link(TT,SS,INF); int tmp=G.dinic(); return tmp==inflow; } int get(int dif) { if (!pwork(dif)) return 0; G.S=S; G.T=T; G.dinic(); G.link(TT,SS,INF); return G.dinic(); } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); memset(du,0,sizeof(du)); for (int i=1;i<=m;i++) scanf("%d%d",&ra[i],&rb[i]); scanf("%d",&k); for (int i=1;i<=k;i++) { scanf("%d%d",&rc[i],&rd[i]); du[rc[i]]++; du[n+rd[i]]++; } int l=0,r=0; for (int i=1;i<=n;i++) r=max(r,du[i]); while(l<r) { int mid=(l+r)/2; if (!check(mid)) l=mid+1; else r=mid; } printf("%d %d\n",r,get(r)); } return 0; }