题目链接:https://nanti.jisuanke.com/t/16959
【中文题意】就是从图中找一条从大连到西安的最短路(这条路必须经过上海),然后使得花费最小,每个城市最多经过一次。
【思路分析】我们可以看到可每个城市最多只走一次,我想到了费用流的拆点可以解决这个问题,然后我们就开始建图,把上海作为汇点,设置一个超级源点,然后超级源点到大连和西安分别有一条路,这两条路的流量分别为1,建边的过程中给边加上费用,然后最后跑一遍最小费用最大流,如果流量小于2,则不存在这样的路,否则输出最小费用。
【AC代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#include<string>
#include<iostream>
#include<map>
using namespace std;
typedef long long ll;
const ll INF = 1e15 + 7;
const int MAXN = 5005;
struct Edge
{
int from;
int to;
int cap;
int flow;
int cost;
};
struct MCMF
{
int n, m, s, t;
vector<Edge> edges;
vector<int> G[MAXN];
int inq[MAXN];
int p[MAXN];
int a[MAXN];
ll dis[MAXN];
void init(int n)
{
this->n = n;
for (int i = 0; i < MAXN; i++)
{
G[i].clear();
}
edges.clear();
}
void AddEdge(int from, int to, int cap, int cost)
{
edges.push_back((Edge)
{
from, to, cap, 0, cost
});
edges.push_back((Edge)
{
to, from, 0, 0, -cost
});
int m = (int)edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
bool BellmanFord(int s, int t, int &flow, ll &cost)
{
for (int i = 0; i <= n; i++)
{
dis[i] = INF;
}
memset(inq, 0, sizeof(inq));
dis[s] = 0, inq[s] = 1, p[s] = 0;
a[s] = 0x3f3f3f3f;
queue<int> q;
q.push(s);
while (!q.empty())
{
int u = q.front();
q.pop();
inq[u] = 0;
for (int i = 0; i < G[u].size(); i++)
{
Edge &e = edges[G[u][i]];
if (e.cap > e.flow && dis[e.to] > dis[u] + e.cost)
{
dis[e.to] = dis[u] + e.cost;
p[e.to] = G[u][i];
a[e.to] = min(a[u], e.cap - e.flow);
if (!inq[e.to])
{
q.push(e.to);
inq[e.to] = 1;
}
}
}
}
if (dis[t] == INF)
{
return false;
}
flow += a[t];
cost += (ll)dis[t] * a[t];
int u = t;
while (u != s)
{
edges[p[u]].flow += a[t];
edges[p[u] ^ 1].flow -= a[t];
u = edges[p[u]].from;
}
return true;
}
ll Mincost(int s, int t)
{
int flow = 0;
ll cost = 0;
while (BellmanFord(s, t, flow, cost));
if (flow < 2)
{
return -1;
}
return cost;
}
};
map<string ,int>ma;
MCMF mcmf;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
mcmf.init(MAXN-1);
int m;
scanf("%d",&m);
ma.clear();
int cnt=4;
ma["Dalian"]=1;
ma["Xian"]=2;
ma["Shanghai"]=3;
string s1,s2;
int w;
for(int i=1;i<=m;i++)
{
cin>>s1>>s2>>w;
if(!ma[s1])ma[s1]=cnt++;
if(!ma[s2])ma[s2]=cnt++;
//printf("%d %d\n",ma[s1],ma[s2]);
int u=ma[s1];
int v=ma[s2];
mcmf.AddEdge(u*2+1,v*2,1,w);
mcmf.AddEdge(v*2+1,u*2,1,w);
}
//printf("sss\n");
for(int i=1;i<cnt;i++)
{
mcmf.AddEdge(2*i,2*i+1,1,0);
}
mcmf.AddEdge(0,2,1,0);
mcmf.AddEdge(0,4,1,0);
ll re=mcmf.Mincost(0,6);
//printf("%d %d\n",re.first,re.second);
printf("%lld\n",re);
}
return 0;
}