[ZJOI2010]网络扩容
Posted skylee的OI博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ZJOI2010]网络扩容相关的知识,希望对你有一定的参考价值。
OJ题号:
BZOJ1834、洛谷2604
思路:
对于第一问,直接跑一遍最大流即可。
对于第二问,将每条边分成两种情况,即将每条边拆成两个:
不需扩容,即残量大于零时,相当于这条边费用为$0$;
需要扩容,即残量等于零时,可以扩容很多次,将残量设为$inf$或者$k$(实际上最多扩容$k$次)。
由于$k≤10$,跑$k$遍流量为$1$的最小费用流即可。
1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 #include<cstring> 6 inline int getint() { 7 char ch; 8 while(!isdigit(ch=getchar())); 9 int x=ch^‘0‘; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^‘0‘); 11 return x; 12 } 13 const int inf=0x7fffffff; 14 int n,m,k,s,t; 15 struct Edge { 16 int from,to,remain,cost; 17 }; 18 const int E=20000,V=1001; 19 Edge e[E]; 20 std::vector<int> g[V]; 21 int sz=0; 22 inline void add_edge(const int u,const int v,const int w,const int c) { 23 e[sz]=(Edge){u,v,w,c}; 24 g[u].push_back(sz); 25 sz++; 26 } 27 int p[V],a[V]; 28 inline int MFAugment() { 29 memset(a,0,sizeof a); 30 a[s]=inf; 31 std::queue<int> q; 32 q.push(s); 33 while(!q.empty()&&!a[t]) { 34 int x=q.front(); 35 q.pop(); 36 for(unsigned i=0;i<g[x].size();i++) { 37 Edge &y=e[g[x][i]]; 38 if(!a[y.to]&&y.remain) { 39 p[y.to]=g[x][i]; 40 a[y.to]=std::min(a[x],y.remain); 41 q.push(y.to); 42 } 43 } 44 } 45 return a[t]; 46 } 47 inline int MF() { 48 int maxflow=0; 49 while(int flow=MFAugment()) { 50 for(int i=t;i!=s;i=e[p[i]].from) { 51 e[p[i]].remain-=flow; 52 e[p[i]^1].remain+=flow; 53 } 54 maxflow+=flow; 55 } 56 return maxflow; 57 } 58 int d[V]; 59 bool inq[V]; 60 inline int MCAugment() { 61 d[s]=0; 62 for(int i=2;i<=t;i++) d[i]=inf; 63 std::queue<int> q; 64 q.push(s); 65 memset(inq,0,sizeof inq); 66 inq[s]=true; 67 while(!q.empty()) { 68 int x=q.front(); 69 q.pop(); 70 inq[x]=false; 71 for(unsigned i=0;i<g[x].size();i++) { 72 Edge &y=e[g[x][i]]; 73 if((d[x]+y.cost<d[y.to])&&y.remain&&(y.cost>=0)) { 74 d[y.to]=d[x]+y.cost; 75 p[y.to]=g[x][i]; 76 if(!inq[y.to]) { 77 q.push(y.to); 78 inq[y.to]=true; 79 } 80 } 81 } 82 } 83 return d[t]; 84 } 85 inline int MC() { 86 int mincost=0; 87 while(k--) { 88 int cost=MCAugment(); 89 for(int i=t;i!=s;i=e[p[i]].from) { 90 e[p[i]].remain--; 91 e[p[i]^1].remain++; 92 } 93 mincost+=cost; 94 } 95 return mincost; 96 } 97 int main() { 98 n=getint(),m=getint(),k=getint(); 99 s=1,t=n; 100 while(m--) { 101 int u=getint(),v=getint(),w=getint(),c=getint(); 102 add_edge(u,v,w,c); 103 add_edge(v,u,0,-c); 104 } 105 printf("%d ",MF()); 106 int oldsz=sz; 107 for(int i=0;i<oldsz;i++) { 108 int u=e[i].from,v=e[i].to,w=e[i].remain,c=e[i].cost; 109 e[i]=(Edge){u,v,w,0}; 110 add_edge(u,v,inf,c); 111 } 112 printf("%d\n",MC()); 113 return 0; 114 }
以上是关于[ZJOI2010]网络扩容的主要内容,如果未能解决你的问题,请参考以下文章