此处过滤最水的匈牙利算法。
最大流&最小割:https://www.lydsy.com/JudgeOnline/problem.php?id=2127
#include<cstdio> #include<algorithm> #include<cstring> #define FOR(x,y) for(int i=1;i<=x;i++)for(int j=1;j<=y;j++) const int N=50100,M=3e5+7; using namespace std; int n,m,T,cnt,tot,ans,hd[N],lv[N],q[N],v[M],nxt[M],w[M]; void adde(int x,int y,int z) { v[++cnt]=y,w[cnt]=z,nxt[cnt]=hd[x],hd[x]=cnt; v[++cnt]=x,w[cnt]=0,nxt[cnt]=hd[y],hd[y]=cnt; } bool bfs() { int qs=0,qe=1; memset(q,0,sizeof q); memset(lv,0,sizeof lv); q[0]=0,lv[0]=1; while(qs<qe) { int u=q[qs++]; if(u==T)break; for(int i=hd[u];i;i=nxt[i]) if(w[i]&&!lv[v[i]]){lv[v[i]]=lv[u]+1;q[qe++]=v[i];} } if(lv[T])return 1;return 0; } int dfs(int u,int low) { if(u==T||!low)return low; int sum=0; for(int i=hd[u];i;i=nxt[i]) if(w[i]&&lv[v[i]]==lv[u]+1) { int tmp=dfs(v[i],min(w[i],low)); sum+=tmp,low-=tmp,w[i]-=tmp,w[i^1]+=tmp; if(!low)return sum; } if(low)lv[u]=-1; return sum; } int id(int x,int y){return(x-1)*m+y;} int main() { scanf("%d%d",&n,&m); T=5*n*m+1,cnt=1,tot=n*m; int x; FOR(n,m)scanf("%d",&x),adde(0,id(i,j),x),ans+=x; FOR(n,m)scanf("%d",&x),adde(id(i,j),T,x),ans+=x; FOR(n-1,m) scanf("%d",&x),tot++,adde(0,tot,x),adde(tot,id(i,j),1e9),adde(tot,id(i+1,j),1e9),ans+=x; FOR(n-1,m) scanf("%d",&x),tot++,adde(tot,T,x),adde(id(i,j),tot,1e9),adde(id(i+1,j),tot,1e9),ans+=x; FOR(n,m-1) scanf("%d",&x),tot++,adde(0,tot,x),adde(tot,id(i,j),1e9),adde(tot,id(i,j+1),1e9),ans+=x; FOR(n,m-1) scanf("%d",&x),tot++,adde(tot,T,x),adde(id(i,j),tot,1e9),adde(id(i,j+1),tot,1e9),ans+=x; while(bfs())ans-=dfs(0,1e9); printf("%d",ans); }
费用流:https://www.luogu.org/problemnew/show/P3705
#include<bits/stdc++.h> using namespace std; const int N=207; struct edge{int u,v,w,nxt;double c;}e[N*N*4]; queue<int>q; int n,S,T,ecnt,hd[N],vis[N],pre[N]; double a[N][N],b[N][N],d[N]; void adde(int x,int y,int z,double c) { e[++ecnt]=(edge){x,y,z,hd[x],c},hd[x]=ecnt; e[++ecnt]=(edge){y,x,0,hd[y],-c},hd[y]=ecnt; } bool spfa() { for(int i=S;i<=T;i++)d[i]=-1e18,pre[i]=0; d[S]=0,q.push(S); while(!q.empty()) { int u=q.front();q.pop(); vis[u]=0; for(int i=hd[u];i;i=e[i].nxt) if(e[i].w&&d[u]+e[i].c>d[e[i].v]) { pre[e[i].v]=i,d[e[i].v]=d[u]+e[i].c; if(!vis[e[i].v])q.push(e[i].v),vis[e[i].v]=1; } } return d[T]>-1e18; } bool check() { double ret=0; while(spfa()) { int mn=1e9+7; for(int i=pre[T];i;i=pre[e[i^1].v])mn=min(mn,e[i].w); for(int i=pre[T];i;i=pre[e[i^1].v])e[i].w-=mn,e[i^1].w+=mn; ret+=mn*d[T]; } return ret>0; } int main() { scanf("%d",&n),T=2*n+1; for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%lf",&a[i][j]); for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%lf",&b[i][j]); double l=0,r=10086,mid; while(r-l>1e-7) { mid=(l+r)/2; ecnt=1; memset(hd,0,sizeof hd); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) adde(i,j+n,1,a[i][j]-mid*b[i][j]); for(int i=1;i<=n;i++)adde(S,i,1,0),adde(i+n,T,1,0); if(check())l=mid;else r=mid; } printf("%.6lf",l); }
KM:https://www.luogu.org/problemnew/show/P4412
#include<bits/stdc++.h> using namespace std; const int N=1100,M=21000; struct edge{int u,v,nxt,w,id;}a[M],e[M]; bool is[M]; int n,m,cnt,hd[N],fa[N],deep[N],pre[M],f[N][N],mat[N],lx[N],rx[N],need[N],mp[N][N]; bool vl[N],vr[N]; void add(int x,int y,int z,int id) {e[++cnt]=(edge){x,y,hd[x],z,id};hd[x]=cnt;} void dfs(int u) { for(int i=hd[u];i;i=e[i].nxt) if(e[i].v!=fa[u]) { fa[e[i].v]=u; deep[e[i].v]=deep[u]+1; pre[e[i].v]=i; dfs(e[i].v); } } void build(int u,int i) { int x=a[i].u,y=a[i].v; while(x!=y) { if(deep[x]>deep[y])swap(x,y); int k=pre[y]; f[u][e[k].id]=e[k].w-a[i].w; y=fa[y]; } } bool find(int x) { vl[x]=1; for(int i=1;i<=n;i++) if(!vr[i]) { if(lx[x]+rx[i]==f[x][i]) { vr[i]=1; if(!mat[i]||find(mat[i])) { mat[i]=x; return 1; } } else need[i]=min(need[i],lx[x]+rx[i]-f[x][i]); } return 0; } void km() { memset(mat,0,sizeof mat); memset(lx,0,sizeof lx); memset(rx,0,sizeof rx); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) lx[i]=max(lx[i],f[i][j]); for(int i=1;i<=n;i++) { memset(need,63,sizeof need); while(1) { memset(vl,0,sizeof vl); memset(vr,0,sizeof vr); if(find(i))break; int d=2147483647; for(int j=1;j<=n;j++)if(!vr[j])d=min(d,need[j]); for(int j=1;j<=n;j++) { if(vl[j])lx[j]-=d; if(vr[j])rx[j]+=d; else need[j]-=d; } } } int ans=0; for(int i=1;i<=n;i++)ans+=f[mat[i]][i]; printf("%d",ans); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w),mp[a[i].u][a[i].v]=i; for(int i=1,x,y;i<n;i++) { scanf("%d%d",&x,&y); is[mp[x][y]]=1; add(x,y,a[mp[x][y]].w,i); add(y,x,a[mp[x][y]].w,i); } deep[1]=1; dfs(1); for(int i=1,tp=0;i<=m;i++) if(!is[i])build(++tp,i); n=max(n-1,m-n+1); km(); }
有上下界的网络流:https://www.lydsy.com/JudgeOnline/problem.php?id=2502
#include<bits/stdc++.h> using namespace std; const int N=30100,M=500100; struct edge{int v,nxt,c;}e[M]; int n,m,cnt=1,ans,S,T,hd[N],lv[N],q[N]; void add(int u,int v,int w) { e[++cnt]=(edge){v,hd[u],w};hd[u]=cnt; e[++cnt]=(edge){u,hd[v],0};hd[v]=cnt; } bool bfs() { int qs=0,qe=1; memset(lv,0,sizeof lv); q[0]=0;lv[0]=1; while(qs<qe) { int u=q[qs++];if(u==T)break; for(int i=hd[u];i;i=e[i].nxt) if(e[i].c&&!lv[e[i].v])lv[e[i].v]=lv[u]+1,q[qe++]=e[i].v; } return lv[T]; } int dfs(int u,int f) { if(u==T)return f; int sum=0,tmp; for(int i=hd[u];i;i=e[i].nxt) if(e[i].c&&lv[e[i].v]==lv[u]+1) { tmp=dfs(e[i].v,min(f,e[i].c)); sum+=tmp;f-=tmp; e[i].c-=tmp;e[i^1].c+=tmp; } if(!sum)lv[u]=-1; return sum; } void solve(){while(bfs())ans+=dfs(0,1e9);} int main() { scanf("%d",&n); int x,y; for(int i=1;i<=n;i++) { scanf("%d",&x); while(x--) { scanf("%d",&y);m++; add(i,n+2*m-1,1e9);add(n+2*m,y,1e9); add(n+2*m-1,n+2*m,1e9); } } S=n+2*m+1;T=S+1; for(int i=1;i<=n;i++)add(S,i,1e9); for(int i=1;i<=m;i++)add(0,n+2*i,1),add(n+2*i-1,T,1); for(int i=1;i;i++){add(0,S,1);solve();if(ans==m){printf("%d",i);break;}} }
霍尔定理:https://www.lydsy.com/JudgeOnline/problem.php?id=3693
#include<bits/stdc++.h> #define lson l,mid,rt*2 #define rson mid+1,r,rt*2+1 using namespace std; const int N=4e5+7; struct que{int l,r,a;}q[N]; int n,m,a[N],mx[N*4],lazy[N*4]; bool operator<(que a,que b){return a.r<b.r;} void build(int l,int r,int rt) { if(l==r){mx[rt]=a[l]-1;return;} int mid=(l+r)/2; build(lson);build(rson); mx[rt]=max(mx[rt*2],mx[rt*2+1]); } void pushdown(int rt) { if(!lazy[rt])return; lazy[rt*2]+=lazy[rt];mx[rt*2]+=lazy[rt]; lazy[rt*2+1]+=lazy[rt];mx[rt*2+1]+=lazy[rt]; lazy[rt]=0; } void add(int L,int R,int c,int l,int r,int rt) { if(L<=l&&r<=R){mx[rt]+=c;lazy[rt]+=c;return;} int mid=(l+r)/2; pushdown(rt); if(L<=mid)add(L,R,c,lson); if(R>mid)add(L,R,c,rson); mx[rt]=max(mx[rt*2],mx[rt*2+1]); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R)return mx[rt]; pushdown(rt); int mid=(l+r)/2,ret=0; if(L<=mid)ret=max(ret,query(L,R,lson)); if(R>mid)ret=max(ret,query(L,R,rson)); return ret; } int main() { int T;scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); int sum=0,tot=n; for(int i=1;i<=n;i++) { scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].a); q[i].l++,q[i].r++; sum+=q[i].a; if(q[i].l>q[i].r)q[i].r+=m; else q[++tot].l=q[i].l+m,q[tot].r=q[i].r+m,q[tot].a=q[i].a; } if(sum>m){puts("No");continue;} n=tot;tot=0; for(int i=1;i<=n;i++)a[++tot]=q[i].l,a[++tot]=q[i].r; sort(a+1,a+tot+1); tot=unique(a+1,a+tot+1)-a-1; memset(lazy,0,sizeof lazy); memset(mx,0,sizeof mx); build(1,tot,1); sort(q+1,q+n+1); bool flag=1; for(int i=1;i<=n;i++) { q[i].l=lower_bound(a+1,a+tot+1,q[i].l)-a; q[i].r=lower_bound(a+1,a+tot+1,q[i].r)-a; add(1,q[i].l,q[i].a,1,tot,1); if(query(1,q[i].r,1,tot,1)>a[q[i].r]){flag=0;break;} } if(flag)puts("Yes");else puts("No"); } }
完结撒花