简析
看到 \(0\le k\le10\),\(k\) 非常的小,那么正解可以暴力。
预处理的话,我们考虑先把起点 \(s\) 和每一个特殊点做 \(k+1\) 次最短路。
然后暴力枚举 \(O(n!)\) 的顺序,顺序走一次,记录最小值,输出 。
虽说很简单但还是很考验码力。
Warning:当 \(k=0\) 时要特判,否则会出现意想不到的错误。
代码
#include<bits/stdc++.h>
using namespace std;
using LL=long long;
const LL N=5e4+5,M=1e5+5;
struct edge {
LL to,nxt,w;
} e[M];
LL n,cnt,head[N],dis[N];
bitset<N> vis;
void add(LL u,LL v,LL w) {
e[++cnt].to=v,e[cnt].w=w,e[cnt].nxt=head[u],head[u]=cnt;
}
priority_queue<pair<LL,LL>> q;
void dijkstra(LL u) {
q.push(make_pair(0,u)),dis[u]=0;
while(q.size()) {
u=q.top().second,q.pop();
if(vis[u]) {
continue;
}
vis[u]=1;
for(LL i=head[u],v,w; i; i=e[i].nxt) {
v=e[i].to,w=e[i].w;
if(dis[u]+w<dis[v]) {
dis[v]=dis[u]+w;
q.push(make_pair(-dis[v],v));
}
}
}
}
void dijkstra(LL u,LL *dis) {
q.push(make_pair(0,u)),dis[u]=0;
while(q.size()) {
u=q.top().second,q.pop();
if(vis[u]) {
continue;
}
vis[u]=1;
for(LL i=head[u],v,w; i; i=e[i].nxt) {
v=e[i].to,w=e[i].w;
if(dis[u]+w<dis[v]) {
dis[v]=dis[u]+w;
q.push(make_pair(-dis[v],v));
}
}
}
}
LL key[15],ge[15][N],a[15];
int main() {
LL n,m,k,s,t;
scanf("%lld %lld %lld %lld %lld",&n,&m,&k,&s,&t);
for(LL i=1,u,v,w; i<=m; i++) {
scanf("%lld %lld %lld",&u,&v,&w),add(u,v,w);
}
for(LL i=1; i<=k; i++) {
memset(ge[i],0x3f,sizeof(ge[i])),vis=0;
scanf("%lld",key+i);
if(key[i]==s||key[i]==t) {
i--,k--;
continue;
}
dijkstra(key[i],ge[i]),a[i]=i;
}
memset(dis,0x3f,sizeof(dis)),vis=0,dijkstra(s);
LL minn=1e15;
do {
LL tmp=dis[key[a[1]]];
for(LL i=1; i<k; i++) {
tmp+=ge[a[i]][key[a[i+1]]];
}
tmp+=ge[a[k]][t];
if(!k) {
tmp=dis[t];
}
minn=min(minn,tmp);
} while(next_permutation(a+1,a+k+1));
if(minn>=1e12) {
puts("-1");
return 0;
}
printf("%lld",minn);
return 0;
}