Problem : Double Shortest Paths
Description : Alice和Bob要从1走到n,每条边第一次被走过的时候的权值是cost,第二次被走过的时候是cost+re。
Solution : 费用流裸题,对于将源点连到1,将n连到汇点,对于每条边建立两条边,一条费用为cost,另一条费用为cost+re,然后跑一遍最小费用最大流答案就出来了。
Code (C++) :
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define N 550
#define inf 0x3f3f3f3f
using namespace std;
int visit[N],n,t;
int dis[N];
int head[N];
int pre[N];
struct edge
{
int u;
int v;
int cost;
int cap;
int flow;
int next;
edge() {}
edge(int u,int v,int cost,int cap,int flow,int next)
{
this->u=u;
this->v=v;
this->cost=cost;
this->cap=cap;
this->flow=flow;
this->next=next;
}
} e[N*N];
void addedge(int u,int v,int cap,int c)
{
e[t]=edge(u,v,c,cap,0,head[u]);
head[u]=t++;
e[t]=edge(v,u,-c,0,0,head[v]);
head[v]=t++;
}
bool Spfa(int src,int des)
{
int u,v,weight;
memset(visit,0,sizeof(visit));
memset(dis,inf,sizeof(dis));
memset(pre,-1,sizeof(pre));
dis[src]=0;
queue<int>q;
while(!q.empty())
q.pop();
q.push(src);
visit[src]=1;
while(!q.empty())
{
u=q.front();
q.pop();
visit[u]=0;
for(int i=head[u]; i!=-1; i=e[i].next)
{
v=e[i].v;
weight=e[i].cost;
if(e[i].cap>e[i].flow&&dis[v]>dis[u]+weight)
{
dis[v]=dis[u]+weight;
pre[v]=i;
if(!visit[v])
{
q.push(v);
visit[v]=1;
}
}
}
}
if(pre[des]==-1)
return false;
else
return true;
}
//返回值是最大流 cost中存的是最小费用
int minCostMaxflow(int src,int des,int &cost)
{
int flow=0;
cost=0;
while(Spfa(src,des))
{
int Min=inf;
for (int i=pre[des]; i!=-1; i=pre[e[i^1].v])
{
if (Min>e[i].cap-e[i].flow)
Min=e[i].cap-e[i].flow;
}
for (int i=pre[des]; i!=-1; i=pre[e[i^1].v])
{
e[i].flow+=Min;
e[i ^ 1].flow-=Min;
cost+= e[i].cost*Min;
}
flow+=Min;
}
return flow;
}
int main()
{
freopen("in.txt","r",stdin);
int m,k=1,u,v,cost,re,ans;
while(~scanf("%d%d",&n,&m))
{
ans=0;
memset(head,-1,sizeof(head));
for(int i=0; i<m; i++)
{
cin>>u>>v>>cost>>re;
addedge(u,v,1,cost);
addedge(u,v,1,cost+re);
}
//起点和终点的流量为2,费用为0
addedge(0,1,2,0);
addedge(n,n+1,2,0);
minCostMaxflow(0,n+1,ans);
printf("Case %d: %d\n",k++,ans);
}
return 0;
}