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