1. 程式人生 > >2017 ACM-ICPC 亞洲區(烏魯木齊賽區)網路賽J

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;  
}