1834: [ZJOI2010]network 网络扩容
Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 3195 Solved: 1655
[ Submit][ Status][ Discuss]
Description
给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求: 1、 在不扩容的情况下,1到N的最大流; 2、 将1到N的最大流增加K所需的最小扩容费用。
Input
输入文件的第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
Output
输出文件一行包含两个整数,分别表示问题1和问题2的答案。
Sample Input
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
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
Sample Output
13 19
30%的数据中,N<=100
100%的数据中,N<=1000,M<=5000,K<=10
30%的数据中,N<=100
100%的数据中,N<=1000,M<=5000,K<=10
HINT
Source
学习了学习了
首先DINIC跑最大流
然后在原来的残量网络上加边
边的权值为扩容的费用cost,容量为INF
而原边的费用为0
再建一个源点S,把S连向1,费用为0,容量为k
跑一边最小费用最大流就好了
代码:
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
const int max_m = 30100;
const int max_n = 1100;
const int INF = 2147483647;
struct data{
int flow,cap,from,to,cost;
}e[max_m];
queue<int> q;
bool vis[max_n],exist[max_n];
int dis[max_n],cur[max_n],pre[max_n],a[max_n];
vector<int> G[max_n];
int from[max_m],to[max_m],cap[max_m],cost[max_m];
int tot = -1,n,m,k,ans = 0;
inline void add1(int u,int v,int w)
{
e[++tot] = (data){0,w,u,v,0};
G[u].push_back(tot);
e[++tot] = (data){w,w,v,u,0};
G[v].push_back(tot);
}
inline int getint()
{
int ret = 0;
char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9')
ret = ret * 10 + c - '0',c = getchar();
return ret;
}
inline bool bfs()
{
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
vis[1] = 1;
q.push(1);
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = 0; i < G[u].size(); i++)
{
data edge = e[G[u][i]];
int v = edge.to;
if (vis[v] || edge.flow == edge.cap) continue;
dis[v] = dis[u] + 1;
vis[v] = 1;
q.push(v);
}
}
return vis[n];
}
inline int dinic(int o,int a)
{
if (o == n || a == 0) return a;
int flow = 0;
for (int& i = cur[o]; i < G[o].size(); i++)
{
data& edge = e[G[o][i]];
int v = edge.to;
if (dis[v] != dis[o] + 1) continue;
int f = dinic(v,min(a,edge.cap - edge.flow));
if (f)
{
edge.flow += f;
e[G[o][i] ^ 1].flow -= f;
flow += f;
a -= f;
if (a == 0) break;
}
}
return flow;
}
inline void add2(int u,int v,int w,int c)
{
e[++tot] = (data){0,w,u,v,c};
G[u].push_back(tot);
e[++tot] = (data){w,w,v,u,-c};
G[v].push_back(tot);
}
inline bool spfa()
{
for (int i = 1; i <= n; i++)
dis[i] = INF;
q.push(0);
exist[0] = 1;
a[0] = INF;
while (!q.empty())
{
int u = q.front();
q.pop();
exist[u] = 0;
for (int i = 0; i < G[u].size(); i++)
{
data edge = e[G[u][i]];
int v = edge.to;
if (edge.flow == edge.cap) continue;
if (dis[u] + edge.cost < dis[v])
{
pre[v] = G[u][i];
dis[v] = dis[u] + edge.cost;
a[v] = min(a[u],edge.cap - edge.flow);
if (!exist[v])
{
exist[v] = 1;
q.push(v);
}
}
}
}
if (dis[n] == INF) return 0;
int flow = a[n];
ans += a[n] * dis[n];
int u = n;
while (u != 0)
{
e[pre[u]].flow += flow;
e[pre[u] ^ 1].flow -= flow;
u = e[pre[u]].from;
}
return true;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for (int i = 1; i <= m; i++)
{
from[i] = getint(); to[i] = getint(); cap[i] = getint(); cost[i] = getint();
add1(from[i],to[i],cap[i]);
}
int maxflow = 0;
while (bfs())
{
memset(cur,0,sizeof(cur));
maxflow += dinic(1,INF);
}
printf("%d ",maxflow);
for (int i = 1; i <= m; i++)
add2(from[i],to[i],INF,cost[i]);
add1(0,1,k);
while (spfa());
printf("%d",ans);
return 0;
}