您的位置:首页 > 理论基础 > 计算机网络

【最大流/费用流】BZOJ1834-[ZJOI2010]network 网络扩容

2016-03-01 15:51 489 查看
【题目大意】

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

【思路】

问题用Dinic搞一搞。问题二可以看出是费用流。

(1)残余网络中边还有一些容量,而如果利用这些容量,是不需要花费新的费用的。则将这些边的费用设置为0。

(2)对于原有的边,添加一条起点、终点相同的点,容量设置为INF,费用设置为一开始输入的扩容费用。再添加一个超级源点,和1之间添加一条边,容量为K,费用为0。

所谓的费用流,就是将EK中每一次搜索改为关于单位费用的SPFA即可,其余板块类似。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int MAXN=1000+50;
const int MAXM=5000+50;
const int INF=0x7fffffff;
int n,m,k;//点数边数和需要扩充的容量
struct node
{
int to,cap,pos,w;
};
vector<node> E[MAXN];
int vis[MAXN];
int dis[MAXN];
int U[MAXM],V[MAXM],C[MAXM],W[MAXM];
int pre[MAXN],preedge[MAXN];//记录每次SPFA中每一个节点的前驱,以及当前节点在前驱的vector中是第几条边

void addedge(int u,int v,int c,int w)
{
E[u].push_back((node){v,c,E[v].size(),w});
E[v].push_back((node){u,0,E[u].size()-1,-w});/*失误把这里敲成了E[u],看了好久才看出来T T*/
}

void init()
{
scanf("%d%d%d",&n,&m,&k);
for (int i=0;i<m;i++)
{
scanf("%d%d%d%d",&U[i],&V[i],&C[i],&W[i]);
addedge(U[i],V[i],C[i],0);
}
}

int bfs()
{
queue<int> que;
memset(dis,-1,sizeof(dis));
dis[1]=0;
que.push(1);
while (!que.empty())
{
int head=que.front();que.pop();
for (int i=0;i<E[head].size();i++)
{
node tmp=E[head][i];
if (dis[tmp.to]==-1 && tmp.cap>0)
{
dis[tmp.to]=dis[head]+1;
que.push(tmp.to);
}
}
}
if (dis
==-1) return 0;
else return 1;
}

int dfs(int s,int e,int f)
{
vis[s]=1;
if (s==e) return f;
for (int i=0;i<E[s].size();i++)
{
node& tmp=E[s][i];
if (!vis[tmp.to] && tmp.cap>0 && dis[tmp.to]==dis[s]+1)
{
int delta=dfs(tmp.to,e,min(f,tmp.cap));
if (delta>0)
{
tmp.cap-=delta;
E[tmp.to][tmp.pos].cap+=delta;
return delta;
}
}
}
return 0;
}

void dinic()
{
int flow=0;
while (bfs())
{
memset(vis,0,sizeof(vis));
int f=dfs(1,n,INF);
if (f==0) break;
else flow+=f;
}
cout<<flow<<' ';
}

void rebuild()
{
for (int i=0;i<m;i++) addedge(U[i],V[i],INF,W[i]);
addedge(0,1,k,0);
}

int spfa(int u,int v)
{
memset(vis,0,sizeof(vis));
for (int i=0;i<=n;i++) dis[i]=INF;
memset(pre,-1,sizeof(pre));
queue<int> que;
dis[0]=0;
vis[0]=1;
que.push(0);
while (!que.empty())
{
int head=que.front();
que.pop();
vis[head]=0;
for (int i=0;i<E[head].size();i++)
{
node& tmp=E[head][i];
if (tmp.cap>0 && dis[tmp.to]>dis[head]+tmp.w)
{
dis[tmp.to]=dis[head]+tmp.w;
pre[tmp.to]=head;
preedge[tmp.to]=i;
if (!vis[tmp.to])
{
vis[tmp.to]=1;
que.push(tmp.to);
}
}
}
}
if (dis
==INF) return 0;
else return 1;
}

void mcf()
{
int ans=0;
while (spfa(1,n))
{
int flow=INF;
for (int i=n;pre[i]!=-1;i=pre[i])
flow=min(flow,E[pre[i]][preedge[i]].cap);
for (int i=n;pre[i]!=-1;i=pre[i])
{
node& tmp=E[pre[i]][preedge[i]];
tmp.cap-=flow;
E[tmp.to][tmp.pos].cap+=flow;
ans+=flow*tmp.w;
}
}
cout<<ans<<endl;
}

int main()
{
init();
dinic();
rebuild();
mcf();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: