重要-- 模板 计蒜客-2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛J题Our Journey of Dalian Ends (最小费用最大流)

来源:互联网 发布:淘宝商城卖家出售 编辑:程序博客网 时间:2024/05/16 17:06

Life is a journey, and the road we travel has twists and turns, which sometimes lead us to unexpected places and unexpected people.

Now our journey of Dalian ends. To be carefully considered are the following questions.

Next month in Xian, an essential lesson which we must be present had been scheduled.

But before the lesson, we need to attend a wedding in Shanghai.

We are not willing to pass through a city twice.

All available expressways between cities are known.

What we require is the shortest path, from Dalian to Xian, passing through Shanghai.

Here we go.

Input Format

There are several test cases.

The first line of input contains an integer tt which is the total number of test cases.

For each test case, the first line contains an integer m~(m\le 10000)m (m≤10000) which is the number of known expressways.

Each of the following mm lines describes an expressway which contains two string indicating the names of two cities and an integer indicating the length of the expressway.

The expressway connects two given cities and it is bidirectional.

Output Format

For eact test case, output the shortest path from Dalian to Xian, passing through Shanghai, or output -1?1 if it does not exist.

样例输入

3
2
Dalian Shanghai 3
Shanghai Xian 4
5
Dalian Shanghai 7
Shanghai Nanjing 1
Dalian Nanjing 3
Nanjing Xian 5
Shanghai Xian 8
3
Dalian Nanjing 6
Shanghai Nanjing 7
Nanjing Xian 8
样例输出

7
12
-1
题目链接:
https://nanti.jisuanke.com/t/16959

题意:给定若干个城市,出发点为大连,目的地为西安,但是要求中途必须经过上海,并且图中每个城市只能经过一次,给出m条路(双向道路),走第i条路需要wi代价,求所有满足要求的方案中花费的最小代价,如果没有满足的方案,输出-1。思路:建立一个源点,指向大连和西安。 汇点就是上海。 我们要找两条不重复的路,分别是大连到西安和大连到上海的。所以每条路的容量都是1,费用则是路程。 题目要求每个城市只能走一次,所以拆点,把每个城市分成两个点,中间的容量为1,费用为0。除了上海!上海的连线是2,因为走两次。所以,判断源点到汇点的最大流是否大于等于2.输出费用即可。//最小费用流模板//本模板函数并未传入参数,s,e为源点,汇点是全局变量//#include <iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<queue>#include<cstdlib>#include<vector>#include<map>using namespace std;int vis[100000],dist[100000],pre[100000];//坑人的数据范围const int inf = 0x3f3f3f3f;const int maxn = 100005;int n,maxflow;int top;map<string,int>o;//将真实地点编号int head[maxn],cnt,s,e;struct node{    int u,v,next,w;    int cap;//w即cap}edge[maxn<<4];//加边函数,cap为流量,w为费用void addedge(int u,int v,int cap,int w){    edge[cnt].v = v;    edge[cnt].w = w;    edge[cnt].u = u;    edge[cnt].cap = cap;    edge[cnt].next = head[u];    head[u]=cnt++;   // swap(u,v);    edge[cnt].v = u;    edge[cnt].u = v;    edge[cnt].w = -w;    edge[cnt].cap = 0;    edge[cnt].next = head[v];    head[v]=cnt++;}bool spfa(){    int i;    for(i=0; i<=e; ++i)    {        pre[i]=-1;        dist[i]=inf;        vis[i]=0;    }    queue<int>q;    q.push(s);    dist[s]=0;    while(!q.empty())    {        int u=q.front();        q.pop();        vis[u]=0;        for(i=head[u]; i!=-1; i=edge[i].next)        {            int v=edge[i].v;            int w=edge[i].w;            int cap=edge[i].cap;            int t=dist[u]+w;            if(cap>0&&dist[v]>t)            {                dist[v]=t;                pre[v]=i;                if(!vis[v])                {                    vis[v]=1;                    q.push(v);                }            }        }    }    if(pre[e]==-1)return 0;    return 1;}int get_mincost(){    int ans=0;    while(spfa())    {        int max_flow=inf;        int p=pre[e];        while(p!=-1)        {            max_flow=min(max_flow,edge[p].cap);            p=pre[edge[p].u];        }        p=pre[e];        while(p!=-1)        {            edge[p].cap-=max_flow;            edge[p^1].cap+=max_flow;            ans+=max_flow*edge[p].w;            p=pre[edge[p].u];        }        maxflow += max_flow;        //此处maxflow为同时跑出的最大流    }    return ans;}void init(){    o.clear();    top = 0;    //前向星的初始化    cnt = 0;    memset(head,-1,sizeof(head));    maxflow  = 0;    s = 0,e =4*n+1;}int main(){    int t;    cin>>t;    //本题因为每个城市只能经过一次,所以要拆点    while(t--)    {        cin>>n;        init();        string a,b;        int c,k,u,v;        int nn = 2*n;        //由于没有说题目数据范围,所以最多可能出现2*n个点        for(int i=1;i<=n;i++)        {            cin>>a>>b>>c;            if(o[a]==0)//连接虚点和实点的操作            {                o[a] = ++top,k = 1;                if(a=="Shanghai")                {                    k = 2;                }                //由于本题转化成上海为终点                //所以上海最终可能经过两次                addedge(o[a],o[a]+nn,k,0);            }            if(o[b]==0)            {                o[b] = ++top,k = 1;                if(b=="Shanghai")                {                    k  = 2;                }                addedge(o[b],o[b]+nn,k,0);            }            u = o[a],v = o[b];            //加边的时候,虚点在前(流出),实点在后(流入)            addedge(u+nn,v,1,c);            addedge(v+nn,u,1,c);        }        u = o["Dalian"];        v = o["Xian"];        //连接源点和大连,西安        addedge(s,u,1,0);        addedge(s,v,1,0);        u = o["Shanghai"];        //连接上海和汇点        addedge(u+nn,e,2,0);        int ans = get_mincost();        if(maxflow==2)            cout<<ans<<endl;        else cout<<"-1"<<endl;       // cout<<endl;    }    return 0;}
阅读全文
1 0
原创粉丝点击