2017 ACM-ICPC 区域赛青岛站(现场赛) K.Our Journey of Xian 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 Xian ends. To be carefully considered are the following questions.

A few months later in Qingdao, an essential ACM competition had been scheduled. But before the competition, we need to attend a wedding in Shanghai. And after the competition, we will leave the country from Shanghai, so Pudong International Airport (Pudong in short) is the end of our tour.

Here we have some vital information and missions we have to accomplish.

We have a VIP card of CNAC. For each airport we can enjoy the special VIP services in the departure floor and the arrival floor once respectively. For the pleasure of traveling, it is intolerant without VIP services. That is say that for each airport we can leave from it only once, but without regard to the last flight leaving the country from Pudong, Shanghai. Meanwhile, for each airport we can arrive at it only once.

All as we know, Shanghai has two airports, Hongqiao Airport (Hongqiao in short) and Pudong. Arriving at one and then leaving from another one is a spurned thing. But fortunately there is a nice and evil compensation service. Having a pair of transfer records between Hongqiao and Pudong in both directions, we can obtain a sensible compensation. Actually, we only consider planes in our tour, with the only exception in Shanghai. The exception is that we can arrive and leave Shanghai at different airports. However, if we decide so the compensation described above is necessary. Before the end of our tour, we will pass through Shanghai twice, once for the wedding and another time for the final departure. If we want to obtain the compensation, in the first time we must transfer from Pudong to Hongqiao, and in the second time we will transfer from Hongqiao to Pudong.

Similar transfers between airports in other city are not allowed. If we arrived at a city, we would not go to an airport in an adjacent city by car, bus or interurban railway as well.

Now, all available flights between airports are known. We have plenty of time yet. So we do not have any restriction about the number of times. What we require is the smallest total cost of flights throughout the whole tour.

Here we go.

Input
There are several test cases. The first line of input contains an integer t (1 ≤ t ≤ 160) 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 flights. Each of the following m lines describes a flight which contains two string indicating the names of two airports and an integer between 1 and 255 indicating the cost. The flight connects two given airports and it is bidirectional. The name of each airport is an non-empty string with English letters that are no longer than 10. We use “Xian” to present the only airport in Xian, and use “Qingdao” to present the only airport in Qingdao. The airports in Shanghai are described as “Hongqiao” and “Pudong” respectively.

Output
For each test case, output the smallest total cost, or output −1 if it is impossible.

样例输入

3
4
Xian Hongqiao 3
Xian Pudong 4
Qingdao Hongqiao 4
Qingdao Pudong 3
4
Xian Hongqiao 4
Xian Pudong 3
Qingdao Hongqiao 3
Qingdao Pudong 4
6
Xian Hongqiao 4
Xian Pudong 3
Qingdao Hongqiao 3
Qingdao Pudong 4
Qingdao Xuzhou 1
Xuzhou Hongqiao 1

样例输出

10
9
8

题意

有三个城市:西安,上海,青岛,现在要求在这三个城市之间往返,要求先从西安到上海,再从上海到青岛,再从青岛到上海,问最小花费,每个城市只有一个机场因此只能走一次,但上海有两个机场:虹桥机场和浦东机场,又因为上海有两个机场,所以这里有一个限定条件:只允许从浦东机场前往虹桥机场,也就是说如果从西安来的某条路线到达浦东机场,那么将有两种选择,一种去虹桥机场出发,另一种从浦东出发,但是如果西安的某条路线到达虹桥机场,那么将只有一种选择,从虹桥机场出发。

分析

首先每个机场只能起飞一次,那么我们可以通过拆点的方法,例如需要连一条 u - v 的双向边,那么我们可以将 u 拆成 u -> u’ ,再连接成 u -> u’ -> v -> v’ -> u ,边的流量分别设置为 1、inf、1、inf 。
然后我们建立源点和汇点,源点连向虹桥机场,流量为2,费用为0;源点连向浦东机场,流量为1,费用为0。西安流向汇点,流量为1,费用为0;青岛流向汇点,流量为2,费用为0。

代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e4+8;
const int INF=0x7f7f7f7f;
struct fuck{
    int u,v,cap,w,next;
}edge[maxn<<4];
int head[maxn<<1];
int tol;
void init()
{
    tol=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int cap)
{
    edge[tol].u=u;
    edge[tol].v=v;
    edge[tol].cap=cap;
    edge[tol].w=w;
    edge[tol].next=head[u];
    head[u]=tol++;
    edge[tol].u=v;
    edge[tol].v=u;
    edge[tol].w=-w;
    edge[tol].cap=0;
    edge[tol].next=head[v];
    head[v]=tol++;
}
map<string,int> mp;
int idx;
int getid(char s[])
{
    if(mp.count(s)!=0)
        return mp[s];
    mp[s]=idx;addedge(idx*2-1,idx*2,0,1);idx++;
    return idx-1;
}
int dis[maxn<<1],pre[maxn<<1];
bool vis[maxn<<1];
bool spfa(int sour,int sink)
{
    queue<int>    q;
    q.push(sour);
    memset(dis,INF,sizeof(dis));
    memset(vis,false,sizeof(vis));
    dis[sour]=0;vis[sour]=true;pre[sour]=-1;
    int i,u,v;
    while(!q.empty())
    {
        u=q.front();q.pop();
        vis[u]=false;
        for(i=head[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].v;
            if(edge[i].cap>0&&edge[i].w+dis[u]<dis[v])
            {
                dis[v]=dis[u]+edge[i].w;
                pre[v]=i;
                if(!vis[v])
                    vis[v]=true,q.push(v);
            }
        }
    }
    if(dis[sink]>=INF)   return false;
    return true;
}
void Minicost(int sour,int sink)
{
    int co,fl;
    co=fl=0;
    while(spfa(sour,sink))
    {
        int mi=INF;
        for(int i=pre[sink];i!=-1;i=pre[edge[i^1].v]){
            if(mi>edge[i].cap)
                mi=edge[i].cap;
        }
        for(int i=pre[sink];i!=-1;i=pre[edge[i^1].v]){
            edge[i].cap-=mi;
            edge[i^1].cap+=mi;
        }
        fl+=mi;
        co+=dis[sink]*mi;
    }
    if(fl==3)
        printf("%d\n",co);
    else
        printf("-1\n");
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int m;
        scanf("%d",&m);
        init();idx=1;
        mp.clear();
        mp["Xian"]=idx;addedge(idx*2-1,idx*2,0,1);idx++;
        mp["Qingdao"]=idx;addedge(idx*2-1,idx*2,0,2);idx++;
        mp["Hongqiao"]=idx;addedge(idx*2-1,idx*2,0,2);idx++;
        mp["Pudong"]=idx;addedge(idx*2-1,idx*2,0,1);idx++;
        while(m--)
        {
            char s[12],c[12];
            int w;
            scanf("%s%s%d",s,c,&w);
            int u=getid(s);
            int v=getid(c);
            addedge(u*2,v*2-1,w,INF);
            addedge(v*2,u*2-1,w,INF);
        }
        int sour=0,sink=idx*2-1;
        addedge(sour,3*2-1,0,2);
        addedge(sour,4*2-1,0,1);
        addedge(1*2,sink,0,1);
        addedge(2*2,sink,0,2);
        Minicost(sour,sink);
    }
    return 0;
}
参考

https://blog.csdn.net/wangshuhe963/article/details/78516821
https://www.cnblogs.com/bitch1319453/p/8046738.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值