题意:给一个凸包,保证任意三点不共线(这个条件好像没什么用)。让在凸包上求一条最长路,要求不能经过重复的点,且路径不能自交。点与点的距离按欧氏距离算。
点数为2500数量级,输入的点按顺时针顺序排好(就是不用求凸包了)。
解法:比赛的时候马上莽了一发贪心,枚举起点和两个起始方向,折线地走到终点,交了结果 wa 2,dp只想到了n^3的,于是就去弄第二题线段树了。
正解:易知该路径经过所有的点一定 不比 不经过所有的点差,于是用 dp[i][j][0/1] 表示凸包上 i 到 j 的点全部走完的情况,dp[i][j][0]表示最后落在i点,dp[i][j][1]表示最后落在j点,转移的话:如 dp[i][j][0],一定是:1) 从 j 走到 i;2) 从 i 的相邻右边点走到 i 两种情况之一转移过来的,取个max就行了。
代码写了一发dfs感觉有点慢,于是改成了for循环,好像还是不快。。
记忆化 DFS:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2555;
int n;
double dp[maxn][maxn][2],dist[maxn][maxn],x[maxn],y[maxn];
inline int pre(int x) {
return (x+n-1)%n;
}
inline int nxt(int x) {
return (x+1)%n;
}
inline void getdist(int i,int j) {
dist[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
double dfs(int i,int j,int ty) {
if (dp[i][j][ty]>=0)
return dp[i][j][ty];
int now=!ty?i:j,_pre=pre(i),_nxt=nxt(j);
if (_pre==j)
return 0;
return dp[i][j][ty]=max(dfs(_pre,j,0)+dist[_pre][now],dfs(i,_nxt,1)+dist[now][_nxt]);
}
int main()
{
scanf("%d",&n);
for (int i=0;i<n;++i)
scanf("%lf%lf",&x[i],&y[i]);
for (int i=0;i<n;++i)
for (int j=0;j<n;++j)
getdist(i,j);
for (int i=0;i<n;++i)
for (int j=0;j<n;++j)
for (int k=0;k<2;++k)
dp[i][j][k]=-1;
double res=0;
for (int i=0;i<n;++i)
res=max(res,dfs(i,i,0));
printf("%.12f\n",res);
return 0;
}
For 循环:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2555;
double dp[maxn][maxn][2],dist[maxn][maxn],x[maxn],y[maxn];
int n,pre[maxn],nxt[maxn];
inline int get_pre(int x) {
return (x+n-1)%n;
}
inline int get_nxt(int x) {
return (x+1)%n;
}
inline void getdist(int i,int j) {
dist[i][j]=dist[j][i]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
int main()
{
scanf("%d",&n);
for (int i=0;i<n;++i) {
scanf("%lf%lf",&x[i],&y[i]);
pre[i]=get_pre(i),nxt[i]=get_nxt(i);
}
for (int i=0;i<n;++i)
for (int j=0;j<=i;++j)
getdist(i,j);
for (int k=0;k<n-1;++k) {
for (int i=0;i<n;++i) {
int j=(i+k+1)%n;
dp[i][j][0]=max(dp[nxt[i]][j][0]+dist[nxt[i]][i],dp[nxt[i]][j][1]+dist[i][j]);
dp[i][j][1]=max(dp[i][pre[j]][0]+dist[i][j],dp[i][pre[j]][1]+dist[pre[j]][j]);
}
}
double res=0;
for (int i=0;i<n;++i)
res=max(res,dp[i][(i+n-1)%n][0]);
printf("%.12f\n",res);
return 0;
}