Description
天天突发奇想, 要去 G 地, 于是他搞来了一张地图, 看怎么走才好。
地图上有很多城市, G 地也是一座城市。 每两座城市之间都可能有直达方法, 也有可能 两座城市之间并不能直接相通, 而要通过其他的城市转达。 对于两个城市之间的直达方法, 需要一定的时间, 当然, 如果从 A 城市到 B 城市的直达方法需要 T 时间, 那么从 B 城市到 A 城市的直达方法也是 T 时间。
天天想要用最短的时间到达 G 地, 但是有个问题, 他发现, 地图上有些城市对他很有 吸引力。 所以他要在经过这些城市的基础上时间最短。
天天已经用 1、 2、 3、 4、 5……n 标记了他可能经过的城市( 1 代表出发地, n 代表 G 地), 但是眼花缭乱的地图让他感到烦恼。 他请你来解决这个问题, 告诉他最小需要多少时 间到达 G 地。
Input
第一行是三个正整数 n 和 m, t, n 表示总共有多少个城市( 包括出发地和 G 地), 城市 数不会超过 200 个; m 是城市的直达路线数( 1<=m<=20000), t 表示一定去的城市数 0<=t<=10 ( 不包括出发地和 G 地)。
接下来一行有 t 个整数, 表示一定要去的城市。
接下来 m 行, 每行包含三个正整数, 前两个数表示分别代表一个城市, 第三个数是这 两个城市之间的直达时间。 直达时间不会超过 1000000。
Output
输出一个数, 题目要求的得最短时间。
Sample Input
5 10 2
2 3
1 2 5
1 3 45
1 4 61
1 5 81
2 3 9
2 4 91
2 5 4
3 4 74
3 5 42
4 5 61
Sample Output
27
数据范围:
1<=n<=200
1<=m<=20000
0<=t<=10
Source
最短路 ,搜索, 动态规划, 状态压缩
Solution
超超超超级类似与售货员的难题,先走一遍floyed找最短路,然后dfs,找到ans最小值即可
求最短路,优秀的暴力有30左右
Code
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
int road[201][201],des[201],ans;
bool vis[201];
int n,m,t;
void dfs(int x,int dis,int num)//现在所在城市,从起始点到这个城市已经走过的距离,从起始点到这个城市已经到过的城市数量
{
if(num==t)//如果到过的城市已经符合要求
{
if(dis+road[x][n]<ans)//如果可以更新答案
ans=dis+road[x][n];//更新答案
return ;
}
for(int i=1;i<=t;i++)//枚举城市
{
if(vis[i])//如果可以到
{
vis[i]=false;//标记为到过
dfs(des[i],dis+road[x][des[i]],num+1);//更改现在所在城市,已走距离,和已到城市数量
vis[i]=true;//回溯
}
}
}
int main()
{
freopen("starhder.in","r",stdin);
freopen("starhder.out","w",stdout);
ans=1000000000;
scanf("%d%d%d",&n,&m,&t);
for(int i=1;i<=t;i++)
scanf("%d",&des[i]);
int x,y,d;
memset(road,289,sizeof(road));
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&d);
// if(d<road[x][y])
road[x][y]=d,road[y][x]=d;
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)//floyed求最短路
{
if(i!=j&&road[i][k]+road[k][j]<road[i][j])
road[i][j]=road[j][i]=road[i][k]+road[k][j];
}
memset(vis,true,sizeof(vis));
dfs(1,0,0);
printf("%d\n",ans);
return 0;
}