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;
}