1. 程式人生 > >Our Journey of Dalian Ends

Our Journey of Dalian Ends

這裡寫圖片描述
這裡寫圖片描述

給定雙向邊,求Dalian到Shanghai再到Xian,途中不經過統一的城市,求最短距離
費用流
源點往Shanghai連邊,城市進行拆點處理(流量為1,確保只經過一次),然後城市之間流量為1,費用為對應距離,最後Dalian和Xian與匯點連邊,跑費用流。如果流量為2那麼費用就是最小距離了。

#include <bits/stdc++.h>
#include <map>
using namespace std;

const int MAXN = 40010;
const int MAXM = 100000;
const int INF = 0x3f3f3f3f
; struct Edge { int to,next,cap,flow,cost; }edge[MAXM]; int head[MAXN],tol; int pre[MAXN],dis[MAXN]; bool vis[MAXN]; int N, sum, m, n, sh;//節點總個數,節點編號從0~N-1 map<string, int> G; void addedge(int u,int v,int cap,int cost) { edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow = 0
; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } void init(/*int n*/) { G.clear(); tol = 0; memset(head,-1,sizeof(head)); scanf("%d", &m); sum = 0
; string s1, s2; int len; n = 0; for (int i = 1; i <= m; i++) { cin >> s1; cin >> s2; cin >> len; sum += len; if (!G[s1]) G[s1] = ++n; if (!G[s2]) G[s2] = ++n; addedge(G[s1]+20000, G[s2], 1, len); addedge(G[s2]+20000, G[s1], 1, len); } sh = G["Shanghai"]; for (int i = 1; i <= n; i++) { if (i == sh) addedge(i, i+20000, 2, 0); else addedge(i, i+20000, 1, 0); } addedge(0, sh, 2, 0); addedge(G["Dalian"], MAXN-1, 1, 0); addedge(G["Xian"], MAXN-1, 1, 0); N = n; } bool spfa(int s,int t) { queue<int>q; for(int i = 0;i < MAXN;i++) { dis[i] = INF; vis[i] = false; pre[i] = -1; } dis[s] = 0; vis[s] = true; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u]; i != -1;i = edge[i].next) { int v = edge[i].to; if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost ) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if (!vis[v]) { vis[v] = true; q.push(v); } } } } if(pre[t] == -1)return false; else return true; } //返回的是最大流,cost存的是最小費用 int minCostMaxflow(int s,int t,int &cost) { int flow = 0; 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; } return flow; } int main() { freopen("input.txt","r",stdin); int T; scanf("%d", &T); while (T--) { init(); if (G["Dalian"] && G["Shanghai"] && G["Xian"]) { int cost = 0; int flow = minCostMaxflow(0, MAXN-1, cost); if (flow < 2) { printf("-1\n"); } else { printf("%d\n", cost); } } else { printf("-1\n"); } } }