题意:给你n条边的图,求从Dalian到Xian经过Shanghai的最短路长度,每个点只能经过一次。
题解:由于只有10000条边,所以点数为100的时候是复杂度最大的图,所以我们考虑用网络流,拆点限制每个点只能走一次,Shanghai连源点,Dalain与Xian连汇点,跑费用流。
AC代码:
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <complex>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cassert>
#include<string>
using namespace std;
typedef long long ll;
#define maxn 200010
#define inf 0x3f3f3f3f
#define rep(i,s,t) for(ll i=s;i<=t;i++)
#define MM 200000
struct MCMF{
struct Edge{
ll from,to,cap,flow,cost,next;
Edge(){}
Edge(ll from,ll to,ll cap,ll flow,ll cost,ll next){
this->from=from;
this->to=to;
this->cap=cap;
this->flow=flow;
this->cost=cost;
this->next=next;
}
}ed[666666];
ll n,m,s,t,head,tail,lnum;
ll vis[MM],dis[MM],pre[MM];//pre 上一条弧
ll cag[MM],que[MM*3],start[MM];//cag 可改进量
void init(){
lnum=0;
rep(i,s,t) start[i]=-1;
}
void add(ll x,ll y,ll v,ll c){
ed[lnum]=Edge(x,y,v,0,c,start[x]);
start[x]=lnum++;
ed[lnum]=Edge(y,x,0,0,-c,start[y]);
start[y]=lnum++;
}
bool spfa(ll& flow,ll& cost){
rep(i,s,t) dis[i]=inf,vis[i]=0;
head=tail=0;
dis[s]=0;vis[s]=1;pre[s]=0;cag[s]=inf;
que[tail++]=s;
while(head<tail){
ll x=que[head++];
vis[x]=0;
for(ll i=start[x];~i;i=ed[i].next){
Edge& e=ed[i];
if(e.cap>e.flow&&dis[e.to]>dis[x]+e.cost){
dis[e.to]=dis[x]+e.cost;
pre[e.to]=i;
cag[e.to]=min(cag[x],e.cap-e.flow);
if(!vis[e.to]){
que[tail++]=e.to;
vis[e.to]=1;
}
}
}
}
if(dis[t]==inf) return false;
flow+=cag[t];
cost+=dis[t]*cag[t];
ll x=t;
while(x!=s){
ed[pre[x]].flow+=cag[t];
ed[pre[x]^1].flow-=cag[t];
x=ed[pre[x]].from;
}
return true;
}
ll Mincost(){
ll flow=0,cost=0;
while((spfa(flow,cost)));
if(flow!=2) return -1;
return cost;
}
}c1;
ll m;
ll n;
map<string,ll>mp;
string s1,s2;
int main(void){
ll t;
scanf("%lld",&t);
while(t--){
n=0;
mp.clear();
scanf("%lld",&m);
c1.n=40000+2;
c1.s=0;
c1.t=40000+1;
c1.init();
for(ll i=0;i<m;i++){
cin>>s1>>s2;
ll d; scanf("%lld",&d);
if(mp[s1]==0){
mp[s1]=++n;
if(s1=="Shanghai");
else c1.add(mp[s1],mp[s1]+20000,1,0);
}
if(mp[s2]==0){
mp[s2]=++n;
if(s2=="Shanghai");
else c1.add(mp[s2],mp[s2]+20000,1,0);
}
if(s1=="Shanghai")c1.add(mp[s1],mp[s2],1,d);
else c1.add(mp[s1]+20000,mp[s2],1,d);
if(s2=="Shanghai")c1.add(mp[s2],mp[s1],1,d);
else c1.add(mp[s2]+20000,mp[s1],1,d);
}
c1.add(c1.s,mp["Shanghai"],2,0);
c1.add(mp["Xian"]+20000,c1.t,1,0);
c1.add(mp["Dalian"]+20000,c1.t,1,0);
ll ans=c1.Mincost();
printf("%lld\n",ans);
}
return 0;
}