n个点m条带权边的无向连通图。边权就是距离。
初始时你在点1,让你依次经过2*k个点,使总距离最小。
定义一个瞬移方式:
(1)你可以从一个传送门花费0距离到达另一个传送门。
(2)初始时每个点都有一个关闭的传送门。
(3)你可以在任何一个点关闭任何一个传送门。
(4)你只能打开当前点的传送门。
(5)同时最多存在两个开启的传送门。
数据范围:
只关注一个传送门的位置即可,因为我们可以在需要的时候在当前位置开启一个传送门,到达另一个传送门。
表示到达第i个点时其中一个传送门在j。
转移方式在注释中,就是把ppt的题解模拟了一下。
#include
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define cl(x) x.clear()
#define all(x) x.begin() , x.end()
#define rep(i , x , n) for(int i = x ; i <= n ; i ++)
#define per(i , n , x) for(int i = n ; i >= x ; i --)
#define mem0(x) memset(x , 0 , sizeof(x))
#define mem_1(x) memset(x , -1 , sizeof(x))
#define mem_inf(x) memset(x , 0x3f , sizeof(x))
#define debug(x) cerr << '*' << x << '\n'
#define ddebug(x , y) cerr << '*' << x << ' ' << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair pii ;
typedef pair pll ;
const int mod = 998244353 ;
const int maxn = 300 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count()) ;
int n , m , p ;
int c[maxn << 1] ;
ll dis[maxn][maxn] ;
ll dp[maxn << 1][maxn] ;
int main()
{
ios ;
cin >> n >> m >> p ;
mem_inf(dis) ;
mem_inf(dp) ;
rep(i , 1 , m)
{
int u , v ;
ll w ;
cin >> u >> v >> w ;
dis[u][v] = min(dis[u][v] , w) ;
dis[v][u] = min(dis[v][u] , w) ;
}
rep(i , 1 , n) dis[i][i] = 0ll ;
rep(k , 1 , n) rep(i , 1 , n) rep(j , 1 , n) dis[i][j] = min(dis[i][j] , dis[i][k] + dis[k][j]) ;
p = p * 2 ;
rep(i , 1 , p) cin >> c[i] ;
dp[0][1] = 0 ;
c[0] = 1 ;
rep(i , 0 , p - 1) rep(j , 1 , n)
{
//1.直接从c[i]走到c[i+1]
dp[i + 1][j] = min(dp[i + 1][j] , dp[i][j] + dis[c[i]][c[i + 1]]) ;
//2.枚举走到c[i+1]之后,传送门的位置变为了哪个节点,设这个节点是k。第二种转移是从c[i]走到k,在k设置传送门,从k传送到j,再从j走到c[i+1]
rep(k , 1 , n) dp[i + 1][k] = min(dp[i + 1][k] , dp[i][j] + dis[c[i]][k] + dis[j][c[i + 1]]) ;
//3.第三种转移是从c[i]传送到j,从j走到k,在k设置传送门,最后从k走到c[i+1]
rep(k , 1 , n) dp[i + 1][k] = min(dp[i + 1][k] , dp[i][j] + dis[j][k] + dis[k][c[i + 1]]) ;
}
ll ans = 1e18 ;
rep(i , 1 , n) ans = min(ans , dp[p][i]) ;
cout << ans << '\n' ;
return 0 ;
}