Life is a journey, and the road we travel has twists and turns, which sometimes lead us to unexpected places and unexpected people.
Now our journey of Dalian ends. To be carefully considered are the following questions.
Next month in Xian, an essential lesson which we must be present had been scheduled.
But before the lesson, we need to attend a wedding in Shanghai.
We are not willing to pass through a city twice.
All available expressways between cities are known.
What we require is the shortest path, from Dalian to Xian, passing through Shanghai.
Here we go.
Input Format
There are several test cases.
The first line of input contains an integer t which is the total number of test cases.
For each test case, the first line contains an integer m (m≤10000) which is the number of known expressways.
Each of the following m lines describes an expressway which contains two string indicating the names of two cities and an integer indicating the length of the expressway.
The expressway connects two given cities and it is bidirectional.
Output Format
For eact test case, output the shortest path from Dalian to Xian, passing through Shanghai, or output −1 if it does not exist.
样例输入
3 2 Dalian Shanghai 3 Shanghai Xian 4 5 Dalian Shanghai 7 Shanghai Nanjing 1 Dalian Nanjing 3 Nanjing Xian 5 Shanghai Xian 8 3 Dalian Nanjing 6 Shanghai Nanjing 7 Nanjing Xian 8
样例输出
7 12 -1
题目来源
题目大意:
我们要从大连到西安,中途必须要先到上海一趟,现在要求每个地方只能去一次,问从大连到西安中途经过上海的最小路径花费。
思路:
①要求每个点只能去一次的话,我们不难想到网络流拆点。
②考虑到要求的是最小路径,那么肯定是最小费用流。我们中间必须经过上海,又因为是无向图,那么我们不妨设定上海为起点,大连和西安为终点,我们要从上海到这两个地方去。
③那么建图:
每个点和其拆点建立一条花费为0流为1的边。
每条原图边建立一条花费为w流为INF的边。
建立源点,连入上海这个点,花费为0.流为2。
建立汇点,将西安和大连连入汇点,花费为0,流为1.
然后跑最小费用最大流,如果流达到2,说明我们可以从上海到两个点,那么输出最小费用即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<map>
#include<iostream>
#include<queue>
using namespace std;
struct node
{
int from;
int to;
int w;
int f;
int num;
int next;
}e[2000000];
int head[150000];
int vis[150000];
int dis[150000];
int pre[150000];
int path[150000];
map<string,int>sss;
int Shanghai,Dalian,Xian;
int n,ss,tt,cont;
void add(int from,int to,int f,int w)
{
e[cont].to=to;
e[cont].f=f;
e[cont].w=w;
e[cont].num=cont;
e[cont].next=head[from];
head[from]=cont++;
}
int SPFA()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=tt;i++)dis[i]=0x3f3f3f3f;
dis[ss]=0;
queue<int >s;
s.push(ss);
while(!s.empty())
{
int u=s.front();
s.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
int f=e[i].f;
if(f&&dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
pre[v]=u;
path[v]=e[i].num;
if(vis[v]==0)
{
vis[v]=1;
s.push(v);
}
}
}
}
if(dis[tt]!=0x3f3f3f3f)return 1;
else return 0;
}
void Slove()
{
int ans=0;
int maxflow=0;
while(SPFA()==1)
{
int minn=0x3f3f3f3f;
for(int i=tt;i!=ss;i=pre[i])
{
minn=min(minn,e[path[i]].f);
}
for(int i=tt;i!=ss;i=pre[i])
{
e[path[i]].f-=minn;
e[path[i]^1].f+=minn;
}
maxflow+=minn;
ans+=dis[tt]*minn;
}
if(maxflow==2)
{
printf("%d\n",ans);
}
else printf("-1\n");
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
sss.clear();
cont=0;
memset(head,-1,sizeof(head));
n=0;
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
char name1[1500],name2[1600];
int w;
scanf("%s%s%d",name1,name2,&w);
if(sss[name1]==0)
{
++n;sss[name1]=n;++n;
}
if(sss[name2]==0)
{
++n;sss[name2]=n;++n;
}
int u=sss[name1],v=sss[name2];
add(u+1,v,0x3f3f3f3f,w);
add(v,u+1,0,-w);
add(v+1,u,0x3f3f3f3f,w);
add(u,v+1,0,-w);
}
for(int i=1;i<=n;i+=2)add(i,i+1,1,0),add(i+1,i,0,0);
if(sss["Dalian"]==0||sss["Shanghai"]==0||sss["Xian"]==0)
{
printf("-1\n");
}
else
{
Dalian=sss["Dalian"];
Shanghai=sss["Shanghai"];
Xian=sss["Xian"];
ss=n+1,tt=ss+1;
add(Shanghai,Shanghai+1,1,0);
add(Shanghai,Shanghai+1,0,0);
add(ss,Shanghai,2,0);
add(Shanghai,ss,0,0);
add(Dalian+1,tt,1,0);
add(Xian+1,tt,1,0);
Slove();
}
}
}