UVA 1347 Tour(DP) 紫書訓練
阿新 • • 發佈:2021-01-17
題目連結:UVA 1347
做題感受:看到題自己想沒啥思路,也想不出將一人來回改成兩人同時走到終點,自己本來的想法是構造一個三維陣列dp[i][j][0]和dp[i][j][1]分別表示過去和回來的狀態,但是寫到後面發現狀態轉移方程寫不出來,不知道該怎麼轉移,感覺主要還是狀態轉移方程太難寫,結合lrj的分析和別人的部落格分析最後才勉強寫出來了。(其實我真沒看出來這跟DAG有特別大關係,我就覺得勉勉強強搭上邊)
(感覺思路分析太長的還是直接看概括吧,個人感覺自己思路分析寫的不太好)
思路:
紫書上寫的挺明白了,其實就是把一個人來回分成兩個人同時到達終點,但是要怎麼定義狀態呢?我們定義dp(i,j)為第一個人在i點,第二個人在j點時,離終點還有多遠,先不用管他怎麼表示多遠,dp(i,j)和dp(j,i)實際上是一樣的,無非就是表示成第二個人在i點,第一個人在j點,其實答案沒有區別,因此我們預設i>j,
dp(i,j)=min(dp(i+1,j)+d(i,i+1),dp(i+1,i)+d(i+1,i)+d(j,i+1)).
最後就是要設定好邊界條件dp[n-1][x]表示即將到達終點,所有點都走過了,只要兩人各走一步就走到終點.
簡要概括思路:一人分成兩人,將狀態定義為dp(i,j),每次只能讓兩個人中的一個能走到i+1的位置(把很長的一步分成一個個小步,每次只到下一個點),設定好邊界dp[n-1][x],最後得出狀態轉移方程dp(i,j)=min(dp(i+1,j)+d(i,i+1),dp(i+1,i)+d(i+1,i)+d(j,i+1)).
d表示距離,dp用來遞迴.
下面是我的程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
int n;
double dp[1005][1005];//表示a在第i個位置,b在第j個位置的時候距離終點還有多遠
struct dian {
double x, y;
dian(double x = 0,double y = 0):x(x),y(y){}//這條沒啥用,可以無視
}a[205];
double d(int i, int j)//計算兩點間距離
{
return sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y));
}
double jie(int i, int j)//遞迴dp
{
if (dp[i][j] > 0)return dp[i][j];
return dp[i][j] = min(jie(i + 1, j) + d(i,i+1), jie(i + 1, i) + d(j,i+1));
}
int main()
{
int i, j;
while (scanf("%d",&n)!=EOF)
{
memset(dp, 0, sizeof(dp));
for (i = 1; i <= n; i++)
{
cin >>a[i].x >> a[i].y;
}
for (i = 1; i < n-1; i++)
{
dp[n - 1][i] = d(n-1,n)+d(i,n);//先將邊界的值定義好
}
double ans = jie(1, 1);//引用遞迴函式
printf("%.2f\n",ans);
}
return 0;
}