2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛J

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



哇..居然是用费用流做..当初想了各种方法..哎..还是做题太少了


建立一个源点,指向大连和西安。 汇点就是上海。 我们要找两条不重复的路,分别是大连到西安和大连到上海的。所以每条路的容量都是1,费用则是路程。 题目要求每个城市只能走一次,所以拆点,把每个城市分成两个点,中间的容量为1,费用为0。除了上海!上海的连线是2,因为走两次。

所以,判断源点到汇点的最大流是否大于等于2.输出费用即可。



//借用网上的代码.至今题目都不重现..无奈

#include<stdio.h>  
#include<algorithm>  
#include<string.h>  
#include<map>  
#include<queue>  
#include<string>  
using namespace std;  
#define ll long long  
const ll maxm = 10005;  
const ll INF = 1e18 + 7;  
struct node  
{  
    ll u, v, flow, cost, next;  
}edge[maxm * 10];  
map<string, ll>p;  
ll cnt, s, t, n, m, sum, FLOW;  
ll head[maxm * 10], dis[maxm * 10], pre[maxm * 10];  
char a[maxm], b[maxm];  
void init()  
{  
    p.clear();  
    cnt = 0, s = 0, t = n * 5 + 1, sum = 0, FLOW = 0;  
    memset(head, -1, sizeof(head));  
}  
void add(ll u, ll v, ll flow, ll cost)  
{  
    edge[cnt].u = u, edge[cnt].v = v;  
    edge[cnt].flow = flow, edge[cnt].cost = cost;  
    edge[cnt].next = head[u], head[u] = cnt++;  
    edge[cnt].u = v, edge[cnt].v = u;  
    edge[cnt].flow = 0, edge[cnt].cost = -cost;  
    edge[cnt].next = head[v], head[v] = cnt++;  
}  
ll bfs()  
{  
    queue<ll>q;  
    for (ll i = 0;i <= t;i++) dis[i] = INF;  
    memset(pre, -1, sizeof(pre));  
    dis[s] = 0, q.push(s);  
    ll rev = 0;  
    while (!q.empty())  
    {  
        ll u = q.front();q.pop();  
        for (ll i = head[u];i != -1;i = edge[i].next)  
        {  
            ll v = edge[i].v;  
            if (dis[v] > dis[u] + edge[i].cost&&edge[i].flow)  
            {  
                dis[v] = dis[u] + edge[i].cost;  
                pre[v] = i, q.push(v);  
            }  
        }  
    }  
    if (dis[t] == INF) return 0;  
    return 1;  
}  
ll MCMF()  
{  
    ll ans = 0, minflow;  
    while (bfs())  
    {  
        minflow = INF;  
        for (ll i = pre[t];i != -1;i = pre[edge[i].u])  
            minflow = min(minflow, edge[i].flow);  
        for (ll i = pre[t];i != -1;i = pre[edge[i].u])  
            edge[i].flow -= minflow, edge[i ^ 1].flow += minflow;  
        ans += dis[t] * minflow;  
        FLOW += minflow;  
    }  
    return ans;  
}  
int main()  
{  
    ll i, j, k, T, c;  
    scanf("%lld", &T);  
    while (T--)  
    {  
        scanf("%lld", &n);  
        init();  
        ll nn = n * 2;  
        for (i = 1;i <= n;i++)  
        {  
            scanf("%s%s%lld", a, b, &c);  
            if (p[a] == 0)  
            {  
                p[a] = ++sum, k = 1;  
                if (strcmp(a, "Shanghai") == 0) k = 2;  
                add(p[a], p[a] + nn, k, 0);                           //这是进行拆点
            }  
            if (p[b] == 0)  
            {  
                p[b] = ++sum, k = 1;  
                if (strcmp(b, "Shanghai") == 0) k = 2;  
                add(p[b], p[b] + nn, k, 0);          //这是进行拆点
            }  
            ll u = p[a], v = p[b];  
            add(u + nn, v, INF, c);     //两点连接
            add(v + nn, u, INF, c);      //!!!反向连接。双向的
        }  
        ll u = p["Dalian"];  
        add(s, u, 1, 0);     //s与大连相连
        u = p["Xian"];  
        add(s, u, 1, 0);    //s与西安相连
        u = p["Shanghai"];  
        add(u + nn, t, 2, 0);     //汇点与上海相连,连接的是u+nn,是拆分后的
        ll ans = MCMF();  
        if (FLOW == 2) printf("%lld\n", ans);  
        else printf("-1\n");  
    }  
    return 0;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值