简介:
给出一个有n个节点,m条边的带权无向图,找到起点S到终点T的最短往返路线不能重复走同一条边
简介:
这道题很像dijkstra求最短路和次短路
但是求解最短路次短路的时候,我们贯彻的是一种贪心思想,并且可以走重边
如果只是简单地把最短路上的边删除,再跑一边最短路,是会出错的
因此这道题就带有一点dp的味道了
既像贪心,又像dp:网络流
这道题的建图很简单,
因为我们要找出最短的两条互不影响的路,所以我们用费用流解决
这样就可以保证找到的一定是全脂和最小的路径
但如果从S到T用多条路怎么办
很简单,我们限制一下流量就好了
设超级源点SS,向S连边,容量为2,费用为0
设超级汇点TT,T向其连边,容量为2,费用为0
只有增广出来的总流量为2时,原问题才有解
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int INF=0x33333333;
const int N=102;
struct node{
int x,y,v,c,nxt;
};
node way[N*N*2];
int st[N],tot,n,m,s,t;
int pre[N],dis[N],ans;
bool in[N];
void add(int u,int w,int z,int cc)
{
tot++;
way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].c=cc;way[tot].nxt=st[u];st[u]=tot;
tot++;
way[tot].x=w;way[tot].y=u;way[tot].v=0;way[tot].c=-cc;way[tot].nxt=st[w];st[w]=tot;
}
int spfa(int s,int t)
{
memset(pre,0,sizeof(pre));
memset(dis,0x33,sizeof(dis));
memset(in,0,sizeof(in));
queue<int> Q;
Q.push(s);
dis[s]=0; in[s]=1;
while (!Q.empty())
{
int now=Q.front(); Q.pop();
in[now]=0;
for (int i=st[now];i!=-1;i=way[i].nxt)
if (way[i].v&&dis[way[i].y]>dis[now]+way[i].c)
{
dis[way[i].y]=dis[now]+way[i].c;
pre[way[i].y]=i;
if (!in[way[i].y])
{
in[way[i].y]=1;
Q.push(way[i].y);
}
}
}
return dis[t]<INF;
}
int doit(int s,int t)
{
ans=0;
int flow=0;
while (spfa(s,t))
{
int sum=INF;
for (int i=t;i!=s;i=way[pre[i]].x)
sum=min(sum,way[pre[i]].v);
ans+=sum*dis[t]; flow+=sum;
for (int i=t;i!=s;i=way[pre[i]].x)
way[pre[i]].v-=sum,
way[pre[i]^1].v+=sum;
}
return flow;
}
int main()
{
while (scanf("%d",&n)!=EOF&&n)
{
memset(st,-1,sizeof(st));
tot=-1;
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
int u,w,z;
scanf("%d%d%d",&u,&w,&z);
add(u,w,1,z);
add(w,u,1,z);
}
s=0; t=n+1;
add(s,1,2,0);
add(n,t,2,0);
int flow=doit(s,t);
if (flow==2) printf("%d\n",ans);
else printf("Back to jail\n");
}
return 0;
}