UVA1347 旅行 Tour(神仙dp状态!)
作者:互联网
做这题犯了好多 nt 的事,在朋友圈发完牢骚了!
记录一下这题的神仙状态设计吧qwq。
讲一下我的心路历程:
一开始:回路?搜索?不可能吧,这是蓝题啊(
经过思考:嗯这大概貌似是个 dp 吧,好像 LIS 的做法?变成两个人的相遇问题。但是很快我发现写不出来。
后来,经过某书的悉心指导,终于体悟了这道题对于无后效的处理。
首先我们考虑为什么能变成相遇问题,去时向右单调,回程向左单调,回程正走反走显然是等价。
接下来进入最精彩的部分。
状态
思考一下类比 LIS 的做法为什么不行,你会发现这个状态的缺陷在于你不知道是否选了一样的点,可能走到了当前的 $i,j$ 时你的 $i$ 和 $j$ 都从 $j-1$ 走了过来,这是不行的。
所以我们要设计一个状态,巧妙的避开这个问题:$dp(i,j)$ 代表从 $1$ 到 $\max{i,j}$ 全部恰好被选过一次,且当前两个人分别在 $i,j$ 两点,最少还需要再走多远。好神仙的状态!但还没完!我们可以继续优化,因为这两个人是对称的,所以 $dp(i,j) = dp(j,i)$ 所以我们可以直接令 $dp(i,j),i > j$ 这样就更方便了一些。
一个好的状态是很容易设计出转移方程的,对于 $i,j$ 两个人,显然只能从 $i+1$ 这个点走过来(根据是我们的状态),所以 $i+1$ 要么走到了 $i$,要么走到了 $j$,所以转移方程就是 $dp(i,j) = \min{dp(i+1,j)+dis(i,i+1),dp(i+1,i)+dis(j,i+1)}$
边界就是在 $i = n - 1$ 的时候,因为二者的相遇点必然是 $n$,且根据状态,除了 $n$ 所有的点我们都走过了,所以边界就是 $dp(n-1,j) = dis(n-1,n) + dis(j,n)$ 让他们两个各走一步,在 $n$ 相遇。
答案呢就是 $dp(2,1) + dis(1,2)$ 没毛病啦。
#include<cstdio> #include<queue> #include<cmath> #include<algorithm> #include<cstring> #define rep(i,a,b) for(register int i=(a);i<=(b);++i) #define Rep(i,a,b) for(register int i=(a);i<(b);++i) #define rrep(i,a,b) for(register int i=(a);i>=(b);--i) using namespace std; template <typename T> inline void read(T &x){ x=0;char ch=getchar();bool f=0; while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); if(f)x=-x; } template <typename T,typename ...Args> inline void read(T &tmp,Args &...tmps){read(tmp);read(tmps...);} const int N = 1005; struct qwq{ double x,y; }a[N]; double dp[N][N]; int n; double inf; inline double po(double x){return x * x;} inline double dis(qwq i,qwq j){ return sqrt(po(i.x - j.x) + po(i.y - j.y)); } inline double get(int i,int j){return dis(a[i],a[j]);} double f(int i,int j){ if(dp[i][j] != inf)return dp[i][j]; if(i == n - 1)return dp[i][j] = (get(n-1,n) + get(j,n)); double x = f(i+1,j) + get(i,i+1); double y = f(i+1,i) + get(j,i+1); return dp[i][j] = min(x,y); } signed main(){ while(scanf("%d",&n) != EOF){ memset(dp,120,sizeof(dp));//一个清double正无穷的好方法 inf = dp[0][0]; rep(i,1,n){ scanf("%lf %lf",&a[i].x,&a[i].y); } printf("%.2lf\n",f(2,1)+get(2,1)); } }
标签:return,get,int,double,UVA1347,Tour,dp,dis 来源: https://www.cnblogs.com/wsxxs/p/16260110.html