1. 程式人生 > 實用技巧 >A Portal(最短路傳輸點,dp)

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\n",ans); return 0; }
View Code