1. 程式人生 > >計蒜客-2017 ACM-ICPC 亞洲區(烏魯木齊賽區)網路賽J題Our Journey of Dalian Ends (最小費用最大流)

計蒜客-2017 ACM-ICPC 亞洲區(烏魯木齊賽區)網路賽J題Our Journey of Dalian Ends (最小費用最大流)

題意:

給定若干個城市,出發點為大連,目的地為西安,但是要求中途必須經過上海,並且圖中每個城市只能經過一次,給出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;    
}

繼續加油~