题目描述

  You are now in a big factory. The factory could be recognized as a graph with n vertices and m edges. Every edge has its length. You have missions to do. The -th mission is going to vertex , picking a block and then sending it to vertex . You should complete the missions in the order from -st to -th. Initially you are standing at vertex .
  You have a gun in your hand. When you are at some vertex , you could shoot the gun at the ground, and then a portal will be built at vertex . When there are two portals in the factory, assuming they are at and , you could transfer between and with no cost (just like an edge connecting and with length ).
  You also have a remote controller in your hand. It allows you to close a portal whenever you want and wherever you are (closing one portal at a time, not all portals at the same time). What's more, there could be at most two existing portals. So if you want to create another portal when there exists two, you must use your controller to close one before you create.
  You need to find the minimum distance you have to walk in order to complete all missions.

输入描述

  First line contains three positive integers separated by spaces.
  Next lines, each contains three integers , indicating a bidirectional edge connecting vertex and with length .
  Next lines, each contains two intergers , indicating the begin and the end of the -th mission.
  , , .
  , .
  .
  The graph is guaranteed to be connected.

输出描述

  Output one integer indicating the minimum distance.

示例1

输入

5 4 2
1 2 1
2 3 1
3 4 1
4 5 1
1 5
2 4

输出

5

说明

  Solution for sample : walk from to , create portals at and when passing by, and then walk from to , then you could use portals to complete the second mission.

示例2

输入

6 10 3
1 1 6
5 6 9
3 5 8
1 4 1
2 4 7
6 6 10
1 4 2
6 5 10
3 5 2
3 1 9
1 5
2 5
4 3

输出

28

示例3

输入

6 10 3
1 1 3
3 1 1
6 2 3
1 6 10
4 1 1
3 1 2
5 6 9
5 4 10
6 3 4
3 4 4
3 5
3 6
6 5

输出

16

分析

  用动态规划求解。
   表示已经完成了第 个任务,当前人在节点 ,传送门在节点 时,行走的最短距离。状态过多,显然会
  贪心地思考,一直创建两个传送门是没有必要的:若要从 传送到 ,当前节点为 ,那么必须要从 走到 再传送到 ;不妨只在 创建一个传送门,走到 后再设置传送门;也就是说,我们可以随时在当前节点创建传送门。因此,只需要在状态中记录一个传送门的位置即可。 表示已经完成了第 个任务,当前人在节点 ,传送门在节点 时,行走的最短距离。需要继续精简状态。
  不妨将 个任务看作一条路径:。一共有 个节点, 表示第 个节点,其中 表示当前人位于节点 ,传送门位于节点 时,行走的最短距离。
  可以证明,只需要三种转移,即可覆盖所有状态:① 直接从 走到 ,不更改传送门位置;② 枚举 ,将传送门的位置更改到 ,从 传送到 ,再从 走到 ,将传送门放在 ,再从 走到 ;③ 枚举 ,将传送门的位置更改到 ,从 走到 ,将传送门放在 ,再从 传送到 ,从 走到

代码

/******************************************************************
Copyright: 11D_Beyonder All Rights Reserved
Author: 11D_Beyonder
Problem ID: 2020牛客暑期多校训练营(第五场) Problem A
Date: 8/24/2020
Description: Dynamic Programming
*******************************************************************/
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int N=705;
//====================
//f[i][j]表示:
// 当前在c[i],传送门在j时;
// 行走的最小路程。
ll f[N][N];
ll dis[N][N];
int c[N];
int n,m;
int t;
int main(){
    int i,j,k;
    cin>>n>>m>>k;
    memset(f,inf,sizeof(f));
    memset(dis,inf,sizeof(dis));
    for(i=1;i<=n;i++) dis[i][i]=0;
    for(i=1;i<=m;i++){
        int u,v;
        ll w;
        scanf("%d%d%lld",&u,&v,&w);
        dis[u][v]=min(dis[u][v],w);
        dis[v][u]=min(dis[v][u],w);
    }
    c[++t]=1;
    for(i=1;i<=k;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        c[++t]=a;
        c[++t]=b;
    }
    //Floyed算法求(x,y)之间的最短路
    for(k=1;k<=n;k++){
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
            }
        }
    }
    for(i=1;i<=n;i++){
        //初始化
        //当前在c[1]
        //传送门设置在i
        f[1][i]=dis[1][i];
    }
    int p,q;
    for(i=2;i<=t;i++){
        //当前在c[i-1],要走向c[i]
        for(p=1;p<=n;p++){
            //当前传送门在p
            //不改变传送门位置,直接走到 c[i]
            f[i][p]=min(f[i][p],f[i-1][p]+dis[c[i-1]][c[i]]);
            for(q=1;q<=n;q++){
                //从c[i-1]传送到p,路程0
                //从p走到q,路程dis[p][q]
                //从q走到a[i],路程dis[q][c[i]]
                f[i][q]=min(f[i][q],f[i-1][p]+dis[p][q]+dis[q][c[i]]);
                //从c[i-1]走到q,路程dis[c[i-1]][q]
                //从q传送到p,路程为0
                //从p走到c[i],路程dis[q][c[i]]
                f[i][q]=min(f[i][q],f[i-1][p]+dis[c[i-1]][q]+dis[p][c[i]]);
            }
        }
    }
    ll ans=inf;
    for(i=1;i<=n;i++){
        ans=min(f[t][i],ans);
    }
    cout<<ans<<endl;
    return 0;
}