計蒜客-2017 ACM-ICPC 亞洲區(烏魯木齊賽區)網路賽J題Our Journey of Dalian Ends (最小費用最大流)
阿新 • • 發佈:2019-01-10
題意:
給定若干個城市,出發點為大連,目的地為西安,但是要求中途必須經過上海,並且圖中每個城市只能經過一次,給出m條路(雙向道路),走第i條路需要wi代價,求所有滿足要求的方案中花費的最小代價,如果沒有滿足的方案,輸出-1。
思路:
相當於求從大連到上海加上西安到上海花費的代價總和最小。所以就是最小費用流,點只可走一次,所以進行拆點,一個入點一個出點,每條路連線至相應的出點到入點,容量為1,花費為0。超級源點與大連、西安建邊容量為1,花費為0,上海的入點作為超級匯點。如果最大流不為2,則表明沒有滿足的方案,否則最小費用即ans。
程式碼:
#include <algorithm> #include <iostream> #include <string.h> #include <string> #include <cstdio> #include <queue> #include <map> #define LL long long using namespace std; const LL _inf = 0x3f3f3f3f3f3f3f3f; const int inf = 0x3f3f3f3f; const int maxn = 40100; const int maxm = 60100; struct node { LL c; int v, w, next; } edge[maxm]; int no, head[maxn]; int t, m, n; int S, T; int vis[maxn]; LL dis[maxn]; queue<int> q; int pre[maxn], rec[maxn]; map<string, int> mp; string s1, s2; void init() { no = 0; memset(head, -1, sizeof head); } inline void add(int u, int v, int w, LL c) { edge[no].v = v; edge[no].w = w; edge[no].c = c; edge[no].next = head[u]; head[u] = no++; edge[no].v = u; edge[no].w = 0; edge[no].c = -c; edge[no].next = head[v]; head[v] = no++; } bool SPFA() { memset(dis, 0x3f3f, sizeof dis); memset(vis, 0, sizeof vis); while(!q.empty()) q.pop(); pre[S] = S; dis[S] = 0; q.push(S); vis[S] = 1; while(!q.empty()) { int top = q.front(); q.pop(); vis[top] = 0; for(int k = head[top]; k != -1; k = edge[k].next) { if(edge[k].w && dis[edge[k].v] > dis[top]+edge[k].c) { dis[edge[k].v] = dis[top]+edge[k].c; pre[edge[k].v] = top; rec[edge[k].v] = k; if(!vis[edge[k].v]) vis[edge[k].v] = 1, q.push(edge[k].v); } } } if(dis[T] == _inf) return false; return true; } pair<int, LL> mincost_maxflow() { LL mincost = 0; int maxflow = 0; while(SPFA()) { int flow = inf; for(int k = T; k != S; k = pre[k]) flow = min(flow, edge[rec[k]].w); maxflow += flow; for(int k = T; k != S; k = pre[k]) { mincost += 1ll*flow*edge[rec[k]].c; edge[rec[k]].w -= flow; edge[rec[k]^1].w += flow; } } return make_pair(maxflow, mincost); } int jg(string ss) { if(mp.find(ss) != mp.end()) return mp[ss]; mp[ss] = ++n; add(n*2-1, n*2, 1, 0); return n; } int mapping() { int u, v, c, dl, sh, xa; scanf("%d", &m); n = 0; mp.clear(); dl = sh = xa = -1; for(int i = 1; i <= m; ++i) { cin >> s1 >> s2; scanf("%d", &c); u = jg(s1); v = jg(s2); add(u*2, v*2-1, 1, c); add(v*2, u*2-1, 1, c); if(s1 == "Dalian") dl = u; if(s2 == "Dalian") dl = v; if(s1 == "Shanghai") sh = u; if(s2 == "Shanghai") sh = v; if(s1 == "Xian") xa = u; if(s2 == "Xian") xa = v; } if(dl == -1 || sh == -1 || xa == -1) return 0; S = 0, T = 2*sh-1; add(S, dl*2-1, 1, 0); add(S, xa*2-1, 1, 0); return 1; } int main() { for(scanf("%d", &t); t--;) { init(); if(!mapping()){puts("-1"); continue;} pair<int, LL> pr = mincost_maxflow(); if(pr.first != 2) puts("-1"); else printf("%lld\n", pr.second); } return 0; }
繼續加油~