bzoj1834: [ZJOI2010]network 网络扩容
这道题分为俩步,第一是求最大流,第二是在第一问的残量网络上求最小费用流。
建图时俩个点直接连2条边,一条容量为f[i],费用为0,另一条容量为inf,费用为c[i].这样就可以跑俩个算法了
第二问设一个虚拟源点S与1连容量为k,费用为0的边,n与一个虚拟汇点T连容量为k,费用为0的边。这样一直跑,最后只会增加k的流量。
记住bool一定要用true和false,用0和1tle了。。不知道为啥,但一定要记住
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 2000 + 10; const int maxm = 40000 + 10; const int INF = 0x3f3f3f3f; int n,m,k,eid = -1,S,T,vnum,l,r; int v[maxm],f[maxm],c[maxm],next[maxm]; int h[maxn],d[maxn],gap[maxn],q[maxn],pre[maxn]; bool inque[maxn]; void add(int a,int b,int F,int C) { v[++eid] = b; f[eid] = F; c[eid] = C; next[eid] = h[a]; h[a] = eid; v[++eid] = a; f[eid] = 0; c[eid] = -C; next[eid] = h[b]; h[b] = eid; } int ISAP(int u,int flow) { if(u == T) return flow; int cur = 0,aug,mindist = vnum; for(int i = h[u]; ~i; i = next[i]) if(f[i] && !c[i] && d[v[i]] + 1 == d[u]) { aug = ISAP(v[i],min(f[i],flow-cur)); f[i] -= aug; f[i^1] += aug; cur += aug; if(cur == flow || d[S] >= vnum) return cur; } if(!cur) { if(!--gap[d[u]]) { d[S] = vnum; return cur; } for(int i = h[u]; ~i; i = next[i]) if(f[i] && !c[i]) mindist = min(mindist,d[v[i]]); ++gap[d[u]=mindist+1]; } return cur; } int max_flow() { int res = 0; gap[0] = vnum = n; S = 1; T = n; while(d[S] < vnum) res += ISAP(S,INF); return res; } void build() { scanf("%d%d%d",&n,&m,&k); memset(h,-1,sizeof(h)); for(int i = 1,a,b,f,c; i <= m ; i++) { scanf("%d%d%d%d",&a,&b,&f,&c); add(a,b,f,0); add(a,b,INF,c); } } bool spfa() { for(int i = 1; i <= T; i++) d[i] = INF; l =0,r = 0; int u; d[S] = 0; inque[q[r++] = S] = true; while(l < r) { inque[u = q[l++]] = false; for(int i = h[u]; ~i ; i = next[i]) if(f[i] && d[v[i]] > d[u] + c[i]) { d[v[i]] = d[u] + c[i]; pre[v[i]] = i; if(!inque[v[i]]) inque[q[r++]=v[i]] = true; } } return (d[T] < INF); } int augment() { int aug = INF,res = 0; for(int i = T; i != S; i = v[pre[i]^1]) { aug = min(aug,f[pre[i]]); } for(int i = T; i != S; i = v[pre[i]^1]) { f[pre[i]] -= aug; f[pre[i]^1] += aug; res += c[pre[i]]*aug; } return res; } int cost_flow() { int res = 0; S = n+1; T = n+2; add(S,1,k,0); add(n,T,k,0); while(spfa()) res += augment(); return res; } void sovle() { printf("%d ",max_flow()); printf("%d\n",cost_flow()); } int main() { build(); sovle(); return 0; }