被虐惨了。。做了好久才做出来。
二、网络扩容(network.c/cpp/pas)
时限:1秒
【问题描述】
给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求:
1、 在不扩容的情况下,1到N的最大流;
2、 将1到N的最大流增加K所需的最小扩容费用。
【输入格式】network.in
输入文件的第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。
接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
【输出格式】network.out
输出文件一行包含两个整数,分别表示问题1和问题2的答案。
【输入样例】
5 8 2
1 2 5 8
2 5 9 9
5 1 6 2
5 1 1 8
1 2 8 7
2 5 4 9
1 2 1 1
1 4 2 1
【输出样例】
13 19
【数据规模】
30%的数据中,N<=100
100%的数据中,N<=1000,M<=5000,K<=10
思想想清楚之后很好理解。主要要翻过那个弯。
求出最大流之后,我们要尽量使用还有残量的边或者价格小的边,因此可以朝最小费用流去想。
但是如果残量还有的边用完了,这条边可能还能够扩容。处理方法就是,把这条边变成两条。。。
一条是原来的边,他的费用是0,一条边是新的边,容量无限(最后在超级源限制总容量为K就行了,现在已经有总流量了,限制为K相当于能够增加K),价格为题目给的。
我们已经求出了最大流,但是根据最大流求出的费用流也许不是最优,但是能够退流(即相当于减小费用),所以最后求出的费用一定是最小的。
一开始考虑错了一个地方,就导致没有退流。我重建边的时候考虑的是原来有没有的边,但没有读入的边也可能需要建边,因为有的反向边在Sap过程中也有了残量,因此他们也要建边。
#include <cstdio>
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
const char fi[] = "network.in";
const char fo[] = "network.out";
long N;long M;long K;
void init_file()
{
freopen(fi,"r",stdin);
freopen(fo,"w",stdout);
}
const long maxn = 1010;
const long MOD = 100000;
struct node
{
long u;
long v;
node* nxt;
node* bck;
long c;
long w;
};
node* head[maxn];
node* head2[maxn];
long rv[maxn][maxn];
long D[maxn];
long DN[maxn];
long dist[maxn];
node* pre[maxn];
long que[MOD];
bool vis[maxn];
long c[maxn][maxn];
long w[maxn][maxn];
void insert(long u,long v,long c,long w)
{
node* nn = new node;
nn-> u = u;
nn-> v = v;
nn-> c = c;
nn-> w = w;
nn-> nxt = head[u];
head[u] = nn;
}
void insert2(long u,long v,long c,long w)
{
node* nn = new node;
nn-> u = u;
nn-> v = v;
nn-> c = c;
nn-> w = w;
nn-> nxt = head2[u];
head2[u] = nn;
}
void readdata()
{
scanf("%ld%ld%ld",&N,&M,&K);
for (long i=1;i<M+1;i++)
{
long u;long v;long _c;long _w;
scanf("%ld%ld%ld%ld",&u,&v,&_c,&_w);
insert(u,v,0,0);
rv[u][v] += _c;
if (w[u][v])
w[u][v] = MIN(w[u][v],_w);
else
w[u][v] = _w;
c[u][v] += _c;
}
}
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
const long inf = 0x7f7f7f7f;
long Sap(long u,long maxflow)
{
if (u == N)
return maxflow;
long tmp = 0;
for (node* vv=head[u];vv;vv=vv->nxt)
{
long v = vv->v;
if (rv[u][v]>0&&D[v]+1==D[u])
{
long fb = Sap(v,MIN(rv[u][v],maxflow-tmp));
tmp += fb;
rv[u][v] -= fb;
rv[v][u] += fb;
if (tmp == maxflow)
return tmp;
}
}
if (D[1]>=N)
return tmp;
DN[D[u]]--;
if (DN[D[u]] == 0)
D[1] = N;
DN[++D[u]]++;
return tmp;
}
bool spfa()
{
for (long i=0;i<N+1;i++)
{
dist[i] = inf;
pre[i] = 0;
}
dist[0] = 0;
long l = 0;
long r = 0;
que[++r] = 0;
while (l != r)
{
l = (l+1) % MOD;
long u = que[l];
vis[u] = false;
for (node* vv=head2[u];vv;vv=vv->nxt)
{
long v = vv->v;
if (vv->c>0 && dist[v]>dist[u]+vv->w)
{
pre[v] = vv;
dist[v] = dist[u]+vv->w;
if (!vis[v])
{
vis[v] = true;
r = (r+1) % MOD;
que[r] = v;
}
}
}
}
return pre[N];
}
void work()
{
DN[0] = N;
long maxflow = 0;
while (D[1] < N)
maxflow += Sap(1,inf);
printf("%ld ",maxflow);
for (long u=0;u<N+1;u++)
{
for (long v=u+1;v<N+1;v++)
{
if (rv[u][v])
insert2(u,v,rv[u][v],0);
if (rv[v][u])
insert2(v,u,rv[v][u],0);
if (rv[u][v] && rv[v][u])
{
head2[u]->bck = head2[v];
head2[v]->bck = head2[u];
}
if (rv[u][v] && !rv[v][u])
head2[u]->bck = 0;
if (rv[v][u] && !rv[u][v])
head2[v]->bck = 0;
if (c[u][v])
insert2(u,v,inf,w[u][v]);
if (c[v][u])
insert2(v,u,inf,w[v][u]);
if (c[u][v] && c[v][u])
{
head2[u]->bck = head2[v];
head2[v]->bck = head2[u];
}
if (c[u][v] && !c[v][u])
head2[u]->bck = 0;
if (c[v][u] && !c[u][v])
head2[v]->bck = 0;
}
}
insert2(0,1,K,0);
head2[0]->bck = 0;
long ans2 = 0;
while (1)
{
if (!spfa()) break;
long min = inf;
node* p = pre[N];
while (p)
{
if (p->c < min)
min = p->c;
p = pre[p->u];
}
ans2 += min*dist[N];
p = pre[N];
while (p)
{
p->c -= min;
if (p->bck)
p->bck->c += min;
p = pre[p->u];
}
}
printf("%ld",ans2);
}
int main()
{
init_file();
readdata();
work();
return 0;
}