A Portal(最短路传输点,dp)

题:https://ac.nowcoder.com/acm/contest/5670/A

题意:给出n个点m条边的有边权连通图,k个任务,每个任务表示为[u,v],表示必须走到u节点再走到v节点,任务必须按1~k次序完成。其中你可以在经过的节点上设置传送点,俩个传送点之间的代价为0,图上最多有2个传送点,问完成k个任务的最小路径和是多少

分析:对于每个任务,由于是要依次完成,所以将k个任务的2*k的点连起来形成一个路径a[i],定义dp[i][j]表示完成了前 i 个任务节点,传送门的位置在 j 节点;

   转移:(1)a[i]直接走向a[i+1];

      (2)dp[i][p]向dp[i+1][q]转移(在p和q设传送点):因为dp[i][p]的传送点在p,而题目条件是只能在走过的地方设传送点,所以路径是a[i]-q-p-a[i+1](而不是a[i]-p-q-a[i+1]);

      (3)直接在a[i]传到p,然后走到q,在q设传送点,再走到a[i+1]。(这里是要达到dp[i+1][q]在q点有传送点)

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define MP make_pair
typedef long long ll;
const int mod=1e9+7;
const int M=303;
const int inf=0x3f3f3f3f;
const ll INF=1e18;
ll dis[M][M],dp[M*2][M];
int a[M*2];
int main(){
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i!=j)
                dis[i][j]=INF;
    for(int i=1;i<=m;i++){
        int u,v;
        ll w;
        scanf("%d%d%lld",&u,&v,&w);
        dis[v][u]=dis[u][v]=min(dis[u][v],w);
    }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    for(int i=1;i<=2*k;i++)
        scanf("%d",&a[i]);
    a[0]=1;
    for(int i=0 ;i<=2*k;i++)
        for(int j=1;j<=n;j++)
            dp[i][j]=INF;
    dp[0][1]=0;
    for(int i=0;i<2*k;i++){
        for(int p=1;p<=n;p++){
            dp[i+1][p]=min(dp[i+1][p],dp[i][p]+dis[a[i]][a[i+1]]);
            for(int q=1;q<=n;q++){
                dp[i+1][q]=min(dp[i+1][q],dp[i][p]+dis[a[i]][q]+dis[p][a[i+1]]);
                dp[i+1][q]=min(dp[i+1][q],dp[i][p]+dis[p][q]+dis[q][a[i+1]]);
            }
        }
    }
    ll ans=INF;
    for(int i=1;i<=n;i++)
        ans=min(ans,dp[2*k][i]);
    printf("%lld
",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/starve/p/13412177.html