【BZOJ 2324】[ZJOI2011]营救皮卡丘 费用流
本人实行诱骗拐卖(利用自然分层与实际意义),正解拼接补充(充分利用最大流限制(不浪费任何一个走出去的机会而不是不浪费任何一个已有的流)与问题转换)
#include <cstdio> #include <cstring> #include <algorithm> const int N=155; const int M=20010; const int K=12; const int Inf=0x3f3f3f3f; const int treat=1000000; const int P=N*2; const int E=N*N*2; int n,m,k; int via[N][N]; struct V{ int to,next,f,c; }c[E]; int head[P],t=1; inline void add(int x,int y,int z,int _){ c[++t].to=y,c[t].next=head[x],c[t].f=z,c[t].c=_,head[x]=t; } int dis[P],anc[P]; int q[P],front,back; bool in[P]; int S,T; inline bool spfa(){ memset(dis,0x3f,sizeof(dis)); in[S]=true,q[back++]=S,dis[S]=0; if(back==P)back=0; while(front!=back){ int x=q[front++];in[x]=false; if(front==P)front=0; for(int i=head[x];i;i=c[i].next) if(c[i].f&&dis[x]+c[i].c<dis[c[i].to]){ dis[c[i].to]=dis[x]+c[i].c,anc[c[i].to]=i; if(!in[c[i].to]){ q[back++]=c[i].to,in[c[i].to]=true; if(back==P)back=0; } } } return dis[T]!=Inf; } inline int shoot(){ int f=Inf; for(int i=anc[T];i;i=anc[c[i^1].to])f=std::min(f,c[i].f); for(int i=anc[T];i;i=anc[c[i^1].to])c[i].f-=f,c[i^1].f+=f; return f*dis[T]; } int main(){ memset(via,0x3f,sizeof(via)); scanf("%d%d%d",&n,&m,&k); ++n; for(int i=1,x,y,z;i<=m;++i){ scanf("%d%d%d",&x,&y,&z); ++x,++y; via[x][y]=via[y][x]=std::min(via[x][y],z); } S=n+n+1,T=n+n+2; for(int i=1;i<=n;++i){ via[i][i]=0; add(i,i+n,1,-treat),add(i+n,i,0,treat); add(i,i+n,k,0),add(i+n,i,0,0); add(i+n,T,k,0),add(T,i+n,0,0); } for(int a=1;a<=n;++a) for(int b=1;b<=n;++b) via[a][b]=std::min(via[a][b],via[a][1]+via[1][b]); for(int i=2;i<=n;++i){ for(int a=1;a<=n;++a) for(int b=1;b<=n;++b) via[a][b]=std::min(via[a][b],via[a][i]+via[i][b]); for(int j=1;j<i;++j){ add(j+n,i,k,via[j][i]); add(i,j+n,0,-via[i][j]); } } add(S,1,k,0); add(1,S,0,0); int ans=0; while(spfa())ans+=shoot(); ans+=n*treat; printf("%d",ans); return 0; }
苟利国家生死以, 岂因祸福避趋之。