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 tt which is the total number of test cases.
For each test case, the first line contains an integer m~(m\le 10000)m (m≤10000) which is the number of known expressways.
Each of the following mm 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−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
题意 给个图,求从dalian到xian经过shanghai的最短路,并且所有的点都只能走一遍。
转化下问题,就可以为从shanghai到dalian的最短路和从shanghai到xian的最短路,每个点只能够走一遍。
分析
网络流中有一类题目,就是给个图,问是否有多条不同的路径【没有相同点】从起点到达终点,解决这类题目,就是用的拆点来使每个点只走一次。
考虑到每个点只能够走一遍,就联想到网络流中的拆点,有因为带上路径费用,所以可以用费用流解决。
我们限制好流量,让从shanghai出发的流,一个到达dalian,一个到xian,汇点最后有2个流就说明从起点可以走两条没有相同点的路径到达,这个时候再输出最小费用就行。
#include<bits/stdc++.h>
using namespace std ;
typedef long long LL ;
#define debug() puts("======")
const int MAXN = 10000*3;
const int MAXM = 100000+10 ;
const int mod = 1e9+7 ;
const int inf = 0x3f3f3f3f;
struct Edge {
int to,cap,flow,cost,next;
}edge[MAXN*10];
int head[MAXN],top;
void init(){
memset(head,-1,sizeof(head));
top=0;
}
void addedge(int a,int b,int w,int c){
edge[top].to=b;edge[top].cap=w;edge[top].flow=0;edge[top].cost=c;edge[top].next=head[a];
head[a]=top++;
edge[top].to=a;edge[top].cap=0;edge[top].flow=0;edge[top].cost=-c;edge[top].next=head[b];
head[b]=top++;
}
map<string,int>mp;
int n,m;
int S,T;
void getmap(){ // 拆点
char st[100],ed[100];
int a,b,c;n=1;
int mm=m;
m+=10; // 因为有m个边最多有m+1个点,我索性多加了些,不影响结果
while(mm--){
scanf("%s %s %d",st,ed,&c);
if(!mp[st]) {
mp[st]=n++;
addedge(mp[st],mp[st]+m,1,0);
}
if(!mp[ed]) {
mp[ed]=n++;
addedge(mp[ed],mp[ed]+m,1,0);
}
a=mp[st];b=mp[ed];
addedge(a+m,b,1,c);
addedge(b+m,a,1,c);
}
}
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
bool spfa(int s,int t){
queue<int>Q;
memset(dis,inf,sizeof(dis));
memset(vis,false,sizeof(vis));
memset(pre,-1,sizeof(pre));
dis[s]=0;vis[s]=true;Q.push(s);
while(!Q.empty()){
int now=Q.front();Q.pop();vis[now]=0;
for(int i=head[now];i!=-1;i=edge[i].next){
Edge e=edge[i];
if(e.cap>e.flow&&dis[e.to]>dis[now]+e.cost){
dis[e.to]=dis[now]+e.cost;
pre[e.to]=i;
if(!vis[e.to]){
vis[e.to]=true;
Q.push(e.to);
}
}
}
}
return pre[t]!=-1;
}
void MCMF(int s,int t,int &flow,int &cost){
flow=cost=0;
while(spfa(s,t)){
int Min=inf;
for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){
if(Min>edge[i].cap-edge[i].flow){
Min=edge[i].cap-edge[i].flow;
}
}
for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){
edge[i].flow+=Min;
edge[i^1].flow-=Min;
cost+=edge[i].cost*Min;
}
flow+=Min;
}
}
void work(){
if(!mp["Shanghai"]||!mp["Dalian"]||!mp["Xian"]) puts("-1");
else {
S=mp["Shanghai"];T=m*2+1;
addedge(S, S + m, 1, 0); // 这里也关键,要想最后能够跑出来2流,必须要加上这,想想为什么?
addedge(mp["Dalian"]+m,T,1,0);
addedge(mp["Xian"]+m,T,1,0);
int flow,ans;
MCMF(S,T,flow,ans);
//printf("flow==%d ans==%d \n",flow,ans);
if(flow!=2) puts("-1");// 说明不能够走到终点。
else printf("%d\n",ans);
}
}
int main(){
int ncase;scanf("%d",&ncase);
while(ncase--){
init();mp.clear();
scanf("%d",&m);
getmap();
work();
}
return 0;
}