2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 [计蒜客] Our Journey of Dalian Ends

传送门

题目大意

在一个无向图上,求大连到西安经过上海的最短路,每个点只能走一次。

思路

考虑费用流,从源点连向大连和西安流量各为1,从上海连向汇点流量为2,通过拆点来限制流量。

代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5, INF = 0x3f3f3f3f;
struct Edge { int v, w, f, nxt; } e[MAXN << 1];
int n, m, S, T, adj[MAXN], c, ans, dis[MAXN], flow, aug[MAXN], pre[MAXN];
bool inq[MAXN];
inline void Add(int u, int v, int w, int f) {
    e[++ c].v = v; e[c].nxt = adj[u]; adj[u] = c; e[c].w = w; e[c].f = f;
    e[++ c].v = u; e[c].nxt = adj[v]; adj[v] = c; e[c].w =-w; e[c].f = 0;
}
map<string, int> mp;
bool SPFA() {
    int u, v;
    for(int i = 1; i <= T; ++ i) dis[i] = 0x3f3f3f3f, aug[i] = 0;
    aug[S] = 0x7fffffff; dis[S] = 0;
    deque<int> q;
    q.push_back(S);
    while(!q.empty()) {
        u = q.front(); q.pop_front(); inq[u] = 0;
        for(int i = adj[u]; i; i = e[i].nxt) {
            v = e[i].v;
            if(e[i].f > 0 && dis[v] > dis[u] + e[i].w) {
                dis[v] = dis[u] + e[i].w; pre[v] = i; aug[v] = min(aug[u], e[i].f);
                if(!inq[v]) {
                    inq[v] = 1;
                    if(!q.empty() && dis[v] <= dis[q.front()]) q.push_front(v);
                    else q.push_back(v);
                }
            }
        }
    }
    return aug[T];
}
void MCMF() {
    ans = 0; pre[S] = -1;
    while(SPFA()) {
        ans += aug[T]*dis[T]; flow += aug[T];
        for(int i = pre[T]; ~i; i = pre[e[i^1].v]) {
            e[i].f -= aug[T];
            e[i^1].f += aug[T];
        }
    }
}
int main() {
    int _t, w; cin >> _t;
    while(_t --) {
        ans = 0; string a, b;
        cin >> m; c = 1; n += 2;
        for(int i = 1; i <= n; ++ i) adj[i] = 0;
        n = 0; mp.clear();
        for(int i = 1; i <= m; ++ i) {
            cin >> a >> b >> w;
            if(!mp[a]) { mp[a] = ++ n; ++ n; }
            if(!mp[b]) { mp[b] = ++ n; ++ n; }
            int u = mp[a], v = mp[b];
            Add(u + 1, v, w, INF);
            Add(v + 1, u, w, INF);
        }
        for(int i = 1; i <= n; i += 2)
            Add(i, i + 1, 0, 1);
        int A = mp["Dalian"],
            B = mp["Xian"],
            C = mp["Shanghai"];
        Add(C, C+1, 0, 1);
        S = n + 1, T = n + 2;
        Add(S, A, 0, 1);
        Add(S, B, 0, 1);
        Add(C+1, T, 0, 2);
        flow = 0; MCMF();
        printf("%d\n", flow == 2 ? ans : -1);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值