【2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛】 J Our Journey of Dalian Ends 【拆点费用流】

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值