[ZJOI2010network 网络扩容]

[关键字]:网络流 最小费用最大流

[题目大意]:给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求: 1、 在不扩容的情况下,1到N的最大流; 2、 将1到N的最大流增加K所需的最小扩容费用。

//=====================================================================================================

[分析]:第一问很好求,第二问也很好求……第二问,要在原有边的基础上加一条容量为∞费用为W的边,再加入一个超级汇点和原汇点连一条容量原最大流加K费用为0的边,跑一边最小费用最大流就行。

[代码]:

View Code
  1 #include<iostream>
2 #include<cstdio>
3 #include<cstdlib>
4 #include<cstring>
5 #define INF 100000
6 using namespace std;
7
8 struct node
9 {
10 int x,y,d1,d2;
11 int op,next;
12 };
13
14 int h[2000],num[2000],b[1200][1200],d[2000];
15 int c[1200][1200],first[2000],now[2000];
16 bool v[2000],a[1200][1200];
17 int n,m,k,s,t,tot=0,ans=0;
18 node e[50000];
19
20 int add(int x,int y,int d1,int d2)
21 {
22 tot++;
23 e[tot].x=x;
24 e[tot].y=y;
25 e[tot].d1=d1;
26 e[tot].d2=d2;
27 e[tot].next=first[x];
28 e[tot].op=tot+1;
29 first[x]=tot;
30 tot++;
31 e[tot].x=y;
32 e[tot].y=x;
33 e[tot].d1=0;
34 e[tot].d2=-d2;
35 e[tot].next=first[y];
36 e[tot].op=tot-1;
37 first[y]=tot;
38 return 0;
39 }
40
41 int find(int u,int flow)
42 {
43 if (u==t) return flow;
44 int temp=flow,pos=n-1;
45 for (int p=first[u];p;p=e[p].next)
46 {
47 if (h[u]==h[e[p].y]+1 && e[p].d1>0)
48 {
49 int f=find(e[p].y,min(e[p].d1,temp));
50 temp-=f;
51 e[p].d1-=f;
52 e[e[p].op].d1+=f;
53 if (!temp || h[s]==n) return flow-temp;
54 }
55 if (e[p].d1>0 && pos>h[e[p].y]) pos=h[e[p].y];
56 }
57 if (temp==flow)
58 {
59 num[h[u]]--;
60 if (num[h[u]]==0) h[s]=n;
61 else
62 {
63 h[u]=pos+1;
64 num[h[u]]++;
65 }
66 }
67 return flow-temp;
68 }
69
70 int augment(int u,int flow)
71 {
72 if (u==t)
73 {
74 ans+=flow*d[s];
75 return flow;
76 }
77 int i,delta;
78 v[u]=1;
79 for (int p=now[u];p;p=e[p].next)
80 {
81 if (e[p].d1>0 && !v[e[p].y] && d[e[p].y]+e[p].d2==d[u])
82 {
83 delta=augment(e[p].y,min(flow,e[p].d1));
84 if (delta>0)
85 {
86 e[p].d1-=delta;
87 e[e[p].op].d1+=delta;
88 now[u]=p;
89 return delta;
90 }
91 }
92 }
93 now[u]=0;
94 return 0;
95 }
96
97 bool augjudge()
98 {
99 int delta=INF;
100 for (int i=s;i<=t;i++)
101 if (v[i])
102 for (int p=first[i];p;p=e[p].next)
103 if (e[p].d1>0 && !v[e[p].y]) delta=min(delta,e[p].d2-d[i]+d[e[p].y]);
104 if (delta==INF) return 0;
105 for (int i=s;i<=t;i++)
106 if (v[i])
107 {
108 d[i]+=delta;
109 v[i]=0;
110 }
111 return 1;
112 }
113
114 int main()
115 {
116 scanf("%d%d%d",&n,&m,&k);
117 memset(c,0,sizeof(c));
118 memset(b,0,sizeof(b));
119 memset(a,0,sizeof(a));
120 for (int i=1;i<=m;i++)
121 {
122 int u,v,C,W;
123 scanf("%d%d%d%d",&u,&v,&C,&W);
124 c[u][v]+=C;
125 if (!a[u][v] || b[u][v]>W) b[u][v]=W;
126 a[u][v]=1;
127 }
128 s=1;
129 t=n;
130 for (int i=1;i<=n;i++)
131 for (int j=1;j<=n;j++)
132 if (a[i][j]) add(i,j,c[i][j],0);
133 memset(h,0,sizeof(h));
134 memset(num,0,sizeof(num));
135 num[0]=n;
136 while (h[s]<n) ans+=find(s,INF);
137 printf("%d ",ans);
138 //==============================================================================
139 ans=0;
140 for (int i=1;i<=n;i++)
141 for (int j=1;j<=n;j++)
142 if (a[i][j]) add(i,j,INF,b[i][j]);
143 n++;
144 t++;
145 add(t-1,t,k,0);
146 do{
147 memcpy(now,first,sizeof(first));
148 while (augment(s,INF)) memset(v,0,sizeof(v));
149 }while (augjudge());
150
151 printf("%d\n",ans);
152 system("pause");
153 return 0;
154 }



转载于:https://www.cnblogs.com/procedure2012/archive/2012/01/21/2328580.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值