链接:
https://www.nowcoder.com/acm/contest/109/E
来源:牛客网
来源:牛客网
题目描述
给定一幅n个点m条边的图和S个一定要经过的点,问从0号点出发,经过这S个点再回到0号点的最短路径长度是多少。
输入描述:
第一行一个整数T(T <= 2)表示数据组数。 对于每组数据,第一行两个整数n,m表示点数和边数(1 <= n, m <= 100,000)。 接下来m行,每行三个整数x, y, z(0 < x, y < n, 0 <= z <= 1000)表示xy之间有一条长度为c的双向边; 接下来一个整数S。(S<=10) 接下来S行每行一个整数表示一定要经过的点。 数据保证有解。
输出描述:
T行,每行一个整数表示答案。
题解:
#include<queue>
#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,m,s,b[15],dis[15][100005],dp[1<<12][15],f[15];
struct node
{
int to,d;
}a[100005];
queue<node>t;
vector<node>q[100005];
void spfa(int st)
{
node tmp;tmp.to=b[st];tmp.d=0;
t.push(tmp);dis[st][b[st]]=0;
while(t.empty()==0)
{
node now=t.front();t.pop();
for(int i=0;i<q[now.to].size();i++)
{
node v=q[now.to][i];
if(dis[st][v.to]>dis[st][now.to]+v.d)
{
dis[st][v.to]=dis[st][now.to]+v.d;
node tt;tt.to=v.to;tt.d=dis[st][v.to];
t.push(tt);
}
}
}
}
int main(void)
{
int T,x,y,z;
scanf("%d",&T);
while(T--)
{
memset(dp,127,sizeof(dp));
memset(dis,127,sizeof(dis));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
node tmp;
tmp.to=y;tmp.d=z;
q[x].push_back(tmp);
tmp.to=x;tmp.d=z;
q[y].push_back(tmp);
}
scanf("%d",&s);
for(int i=1;i<=s;i++)
{
scanf("%d",&b[i]);
spfa(i);
}
spfa(0);
for(int i=0;i<=s;i++)
dp[1<<i][i]=dis[0][b[i]];
for(int i=0;i<(1<<(s+1));i++)
{
for(int j=0;j<=s;j++)
{
if(dp[i][j]>100000000) continue;
for(int k=0;k<=s;k++)
dp[i|(1<<k)][k]=min(dp[i|(1<<k)][k],dp[i][j]+dis[j][b[k]]);
}
}
printf("%d\n",dp[(1<<(s+1))-1][0]);
for(int i=1;i<=n;i++)
q[i].clear();
}
return 0;
}
/*
1
4 6
0 1 1
1 2 1
2 3 1
3 0 1
0 2 5
1 3 5
3
1
2
3
*/