2017ICPC青岛K Our Journey of Xian Ends

Our Journey of Xian Ends
现场赛做到这题还剩1个多小时,首先心态就有些急了。
然后读题的时候比较急躁,题目又臭又长,导致没有发现,如果要在上海的两个机场之间走的话,只有一种走法。
但是由于要经过某两个特殊点,网赛有类似题,于是知道是费用流,先把板子敲上去,敲板子期间队友突然有建图的想法,然后让我来敲建图 。。。
期间一顿混乱,没能很好理解队友的意思,最后连样例都没过就GG了。
赛前准备了这么久的网络流最后还是没过,很是惭愧。

出来后大致听到了容量为2什么的东西,今天自己仔细想了想,如果题意理解清楚的话,其实并不是特别难。
有几点比较重要的地方。

此题其实只有两种走法
1. 西安-虹桥-青岛-浦东
2. 西安-浦东-虹桥-青岛-虹桥-浦东(上海的两个机场之间只有这一种走法,即先从浦东到虹桥,再从虹桥到浦东)
3. 还要注意拆点

这样一来就是经过了两个中间点的费用流。
可以发现,不管怎么样,从虹桥处都会连出两条边。那么把虹桥容量设为2,青岛也是一定会连出两条边,因此容量设为2,其他点连出的边都只有一条,因此容量都是1。

因为要在点上控制容量,因此要拆点,虹桥与青岛容量为2,其他都是1。

连边就是普通的连边,容量INF,因为有点控制流量,不用考虑边。

最后从源点向浦东连容量为1的边,向虹桥连容量为2的边,从终点向西安连容量为1的边,向青岛连容量为2的边,跑费用流即可,最大流为3时有解。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>

using namespace std;
const int MAXN = 10100;
const int MAXM = 500000;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to,cap,flow,cost,nex;
    Edge() {}
    Edge(int to,int cap,int flow,int cost,int nex):to(to),cap(cap),flow(flow),cost(cost),nex(nex) {}
}edge[MAXM];
int dis[MAXN],tot,tol,head[MAXN],pre[MAXN],cnt,n;
map<string,int> mp;
bool vis[MAXN];

struct node
{
    string ss1,ss2;
    int co;
}no[MAXN];

void addedge(int u,int v,int cap,int cost)
{
    edge[tol] = Edge(v,cap,0,cost,head[u]); head[u]=tol++;
    edge[tol] = Edge(u,0,0,-cost,head[v]); head[v]=tol++;
}

void init()
{
    memset(head,-1,sizeof head);
    cnt=tol=tot=0;
    mp.clear();
}

bool spfa(int s,int t)
{
    memset(vis,0,sizeof vis);
    memset(pre,-1,sizeof pre);
    memset(dis,0x3f,sizeof dis);
    queue<int> que;
    que.push(s);
    dis[s] = 0;
    while (!que.empty())
    {
        int u=que.front();que.pop();
        vis[u] = false;
        for (int i=head[u];~i;i=edge[i].nex)
        {
            int v=edge[i].to;
            if (dis[v] > dis[u]+edge[i].cost && edge[i].cap>edge[i].flow)
            {
                dis[v] = dis[u] + edge[i].cost;
                pre[v] = i;
                if (!vis[v])
                {
                    vis[v]=true;
                    que.push(v);
                }
            }
        }
    }
    if (pre[t] != -1)
        return true;
    else
        return false;
}

int MCMF(int s,int t,int &cost)
{
    int flow=0;
    cost=0;
    while (spfa(s,t))
    {
        int tmp = INF;
        for (int i=pre[t];~i;i=pre[edge[i^1].to])
        {
            tmp = min(tmp, edge[i].cap-edge[i].flow );
        }
        for (int i=pre[t];~i;i=pre[edge[i^1].to])
        {
            edge[i].flow += tmp;
            edge[i^1].flow -= tmp;
            cost += tmp*edge[i].cost;
        }
        flow += tmp;
    }
    return flow;
}

int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        init();
        scanf("%d",&n);
        string ss1,ss2;
        for (int i=1;i<=n;i++)
        {
            cin>>no[i].ss1>>no[i].ss2>>no[i].co;
            ss1=no[i].ss1;ss2=no[i].ss2;
            if (!mp[ss1]) mp[ss1] = ++cnt;
            if (!mp[ss2]) mp[ss2] = ++cnt;
        }
        int xa=mp["Xian"],hq=mp["Hongqiao"],pd=mp["Pudong"],qd=mp["Qingdao"];
//        printf("xa=%d hq=%d pd=%d qd=%d\n",xa,hq,pd,qd);
        for (int i=1;i<=n;i++)
        {
            int a1=mp[no[i].ss1],a2=mp[no[i].ss2];
            addedge(a1+cnt,a2,INF,no[i].co);
            addedge(a2+cnt,a1,INF,no[i].co);
        }
        for (int i=1;i<=cnt;i++)
        {
            if (i == hq)
            {
                addedge(i,i+cnt,2,0);
            }
            else if (i == qd)
            {
                addedge(i,i+cnt,2,0);
            }
            else
            {
                addedge(i,i+cnt,1,0);
            }
        }
        addedge(0,pd,1,0);
        addedge(0,hq,2,0);
        addedge(xa+cnt,2*cnt+1,1,0);
        addedge(qd+cnt,2*cnt+1,2,0);
        int cost,flow;
        flow = MCMF(0,2*cnt+1,cost);
        if (flow == 3)
            printf("%d\n",cost);
        else
            printf("-1\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/z631681297/article/details/78619250