問題描述
給定一個n個點m條邊的有向圖,有k個標記點,要求從規定的起點按任意順序經過所有標記點到達規定的終點,問最短的距離是多少。
輸入
第一行5個整數n、m、k、s、t,表示點個數、邊條數、標記點個數、起點編號、終點編號。
接下來m行每行3個整數x、y、z,表示有一條從x到y的長爲z的有向邊。
接下來k行每行一個整數表示標記點編號。
輸出
輸出一個整數,表示最短距離,若沒有方案可行輸出-1。
樣例輸入
3 3 2 1 1
1 2 1
2 3 1
3 1 1
2
3
樣例輸出
3
樣例解釋
路徑爲1->2->3->1。
算法討論
這道題比較容易,我們只要先對於每個特殊點和起點終點都求一遍最短路,算出這些點之間的最短路徑長度,然後枚舉經過特殊點的順序,就能得出最優答案,注意答案會超int。
#include <cstdio>
#include <deque>
#define MAX_N 50006
#define MAX_M 100006
#define maxlongint 0xffffffff
using namespace std;
struct edge
{
int f,t,w,n;
}a[MAX_M];
deque <int> q;
int ls[MAX_N],b[MAX_N],K[MAX_N],n,m,k,s,t;
bool v[MAX_N],f[11];
long long d[11][MAX_N],Min=maxlongint;
void spfa(int p,int s)
{
for (int i=1;i<=n;i++)
d[p][i]=maxlongint;
d[p][s]=0; v[s]=1;
q.push_back(s);
while (!q.empty())
{
int u=q.front(); q.pop_front();
v[u]=0;
for (int i=ls[u];i;i=a[i].n)
if (d[p][u]+a[i].w<d[p][a[i].t])
{
d[p][a[i].t]=d[p][u]+a[i].w;
if (!v[a[i].t])
{
v[a[i].t]=1;
if (q.empty() || d[p][a[i].t]>d[p][q.front()])
q.push_back(a[i].t);
else
q.push_front(a[i].t);
}
}
}
}
void dfs(int dep,int p,long long s)
{
if (dep>k)
{
s+=d[p][t];
if (s<Min)
Min=s;
return;
}
for (int i=1;i<=k;i++)
if (!f[i])
{
f[i]=1;
dfs(dep+1,i,s+d[p][K[i]]);
f[i]=0;
}
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&a[i].f,&a[i].t,&a[i].w);
a[i].n=ls[a[i].f];
ls[a[i].f]=i;
}
spfa(0,s);
for (int i=1;i<=k;i++)
{
scanf("%d",&K[i]);
spfa(i,K[i]);
}
dfs(1,0,0);
if (Min!=maxlongint)
printf("%lld",Min);
else
printf("-1");
}