最小费用流 uva10806

来源:互联网 发布:c语言unicode转字符串 编辑:程序博客网 时间:2024/05/17 01:14

You are a political prisoner in jail. Things are looking grim, but fortunately, your jailmate has come
up with an escape plan. He has found a way for both of you to get out of the cell and run through the
city to the train station, where you will leave the country. Your friend will escape first and run along
the streets of the city to the train station. He will then call you from there on your cellphone (which
somebody smuggled in to you inside a cake), and you will start to run to the same train station. When
you meet your friend there, you will both board a train and be on your way to freedom.
Your friend will be running along the streets during the day, wearing his jail clothes, so people will
notice. This is why you can not follow any of the same streets that your friend follows - the authorities
may be waiting for you there. You have to pick a completely different path (although you may run
across the same intersections as your friend).
What is the earliest time at which you and your friend can board a train?
Problem, in short
Given a weighed, undirected graph, find the shortest path from S to T and back without using the
same edge twice.
Input
The input will contain several test cases. Each test case will begin with an integer n (2 ≤ n ≤ 100)
— the number of nodes (intersections). The jail is at node number 1, and the train station is at node
number n. The next line will contain an integer m — the number of streets. The next m lines will
describe the m streets. Each line will contain 3 integers — the two nodes connected by the street and
the time it takes to run the length of the street (in seconds). No street will be longer than 1000 or
shorter than 1. Each street will connect two different nodes. No pair of nodes will be directly connected
by more than one street. The last test case will be followed by a line containing zero.
Output
For each test case, output a single integer on a line by itself — the number of seconds you and your
friend need between the time he leaves the jail cell and the time both of you board the train. (Assume
that you do not need to wait for the train — they leave every second.) If there is no solution, print
‘Back to jail’.
Sample Input
2
1
1 2 999
3
3
1 3 10
2 1 20
3 2 50
9
12
1 2 10
1 3 10
1 4 10
2 5 10
3 5 10
4 5 10
5 7 10
6 7 10
7 8 10
6 9 10
7 9 10
8 9 10
0
Sample Output
Back to jail
80
Back to jail


【分析】:

题意:无向图,问从点1走到点n,再走回点1,不能走同一个边两次。

转化为费用流网络流,每条边赋值流量为1,然后从1到n跑最大流为2即可,同时求得最小费用。

加一个超级汇点简便运算。

第一次做费用流,有一个很重要的处理需要学习。

对于有向图,要加一条反向边,流量为0,花费为-cost。

作用:如果正向边走过去之后,发现此路不通,想要回去换路,就可以走一遍反向边回去。


对于此题是无向图,有两条正向边+两条反向边

【代码】:

#include<bits/stdc++.h>using namespace std;const int INF=0x3f3f3f3f;const int MAX=1e5+5;struct node{    int s,t,len,cap,flow,next;}e[MAX];//len路长,cap最大流量,flow已流的量int head[MAX],cnt;void add(int u,int v,int len,int cap,int flow=0){    e[cnt]=node{u,v,len,cap,flow,head[u]};    head[u]=cnt++;}int n,m,u,v,len;int dis[MAX];//最短路bool inq[MAX];int f[MAX];//流量int pre[MAX];//前驱边bool spfa(int s,int t,int &flow,int &cost){    for(int i=0;i<=n+1;i++)dis[i]=INF;    memset(inq,0,sizeof(inq));    dis[s]=0;inq[s]=1;f[s]=INF;    queue<int>q;    q.push(s);    while(!q.empty())    {        int u=q.front();q.pop();        inq[u]=0;        for(int i=head[u];~i;i=e[i].next)        {            if(e[i].cap-e[i].flow>0&&dis[e[i].t]>dis[u]+e[i].len)            {                f[e[i].t]=min(f[u],e[i].cap-e[i].flow);                dis[e[i].t]=dis[u]+e[i].len;                pre[e[i].t]=i;                if(!inq[e[i].t])                    q.push(e[i].t),inq[e[i].t]=1;            }        }    }    if(dis[t]==INF)return 0;//没走到终点    flow+=f[t];//本条增广路的流量    cost+=dis[t]*f[t];//花费    for(int u=t;u!=s;u=e[pre[u]].s)    {        e[pre[u]].flow+=f[t];        e[pre[u]^1].flow-=f[t];    }    return 1;}int mincost(int s,int t){    int flow=0,cost=0;    while(spfa(s,t,flow,cost));    if(flow!=2)return -1;    return cost;}int main(){    while(cin>>n,n)    {        cin>>m;        memset(head,-1,sizeof(head));        cnt=0;        while(m--)        {            scanf("%d%d%d",&u,&v,&len);            add(u,v,len,1);            add(v,u,-len,0);//反悔边            add(v,u,len,1);            add(u,v,-len,0);        }        add(n,n+1,0,2);//n+1超级汇点        int ans=mincost(1,n+1);        if(ans<0)puts("Back to jail");        else printf("%d\n",ans);    }}


原创粉丝点击