1 条题解
-
0
自动搬运
来自洛谷,原作者为

ncwzdlsd
终有一日按下删除键,杀死所有的过去。搬运于
2025-08-24 22:45:31,当前版本为作者最后更新于2023-10-12 19:19:46,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
区间 DP。
设计状态 表示经过区间 内的点,当前位置在左/右时的最小花费。
思路是根据已有的区间向外扩展,转移方程
$$\begin{cases} f(l,r,0)=\min(f(l+1,r,0)+dis(l,l+1),f(l+1,r,1)+dis(l,r))\\ f(l,r,1)=\min(f(l,r-1,0)+dis(l,r),f(l,r-1,1)+dis(r-1,r)) \end{cases} $$对于输出方案,转移时记录前驱即可。
时间复杂度 。
代码如下:
#include <bits/stdc++.h> using namespace std; const int maxn=1005; struct node{double x,y;int id;}a[maxn],tmp[maxn]; double f[maxn][maxn][2]; int pre[maxn][maxn][2]; double dis(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));} void print(int l,int r,int op) { if(l==r) return cout<<a[l].id<<' ',void(); if(op) cout<<a[r].id<<' ',print(l,r-1,pre[l][r][op]); else cout<<a[l].id<<' ',print(l+1,r,pre[l][r][op]); } int main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); int n;cin>>n; for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].y,a[i].id=i,tmp[i]=a[i]; int k=1; for(int i=2;i<=n;i++) if(a[i].y>a[k].y) k=i; for(int i=1;i<=k;i++) a[i+n-k]=tmp[i]; for(int i=k+1;i<=n;i++) a[i-k]=tmp[i]; for(int len=2;len<n;len++) for(int i=1,j=len;j<n;i++,j++) { f[i][j][0]=f[i][j][1]=1e18; if(f[i][j][0]>f[i+1][j][0]+dis(i,i+1)) f[i][j][0]=f[i+1][j][0]+dis(i,i+1),pre[i][j][0]=0; if(f[i][j][0]>f[i+1][j][1]+dis(i,j)) f[i][j][0]=f[i+1][j][1]+dis(i,j),pre[i][j][0]=1; if(f[i][j][1]>f[i][j-1][0]+dis(j,i)) f[i][j][1]=f[i][j-1][0]+dis(i,j),pre[i][j][1]=0; if(f[i][j][1]>f[i][j-1][1]+dis(j,j-1)) f[i][j][1]=f[i][j-1][1]+dis(j,j-1),pre[i][j][1]=1; } cout<<a[n].id<<' '; if(f[1][n-1][0]+dis(1,n)>f[1][n-1][1]+dis(n-1,n)) print(1,n-1,1); else print(1,n-1,0); return 0; }
- 1
信息
- ID
- 8450
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者