Our Journey of Dalian Ends
阿新 • • 發佈:2019-01-27
給定雙向邊,求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");
}
}
}