给定平面内凸包,最小化从其最高点开始的任意哈密尔顿路径(认为任意两点之间均可到达)的欧几里得距离,输出最小化的方案。存在 SPJ。
首先对于
考虑正解,发现对于任意两条路径一定不相交,证明是显然的,考虑任意四个点:
显然由于三角形两边之和大于第三边,前者一定优于后者。
所以对于逆时针给定的若干个点,当处于
于是此时问题显然地转化为了区间 DP,考虑将原序列倍长,设状态
转移也十分显然,与 [ABC273F] Hammer 2 类似,即:
xxxxxxxxxx
971
2
3
4
5
6
7
8
9
10
11
12using namespace std;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23template < typename T = int >
24inline T read(void);
25
26int N;
27pair < ld, ld > pts[2100];
28ld dis[2100][2100];
29ld dp[2100][2100][2];
30tuple < int, int, int > frm[2100][2100][2];
31int top(-1); ld topy(-1e8);
32
33int main(){
34 auto CalDis = [](pair < ld, ld > a, pair < ld, ld > b)->ld{
35 return sqrt((a.first - b.first) * (a.first - b.first) + (a.second - b.second) * (a.second - b.second));
36 };
37 auto Update = [](int l, int r, int k, int sl, int sr, int sk, int dl, int dr)->void{
38 if(dp[sl][sr][sk] >= 1e12)return;
39 if(dp[sl][sr][sk] + dis[dl][dr] < dp[l][r][k])
40 dp[l][r][k] = dp[sl][sr][sk] + dis[dl][dr], frm[l][r][k] = {sl, sr, sk};
41 };
42
43 for(int i = 0; i <= 2010; ++i)for(int j = 0; j <= 2010; ++j)for(int k = 0; k <= 1; ++k)dp[i][j][k] = 1e12;
44 N = read();
45 for(int i = 1; i <= N; ++i){
46 scanf("%Lf%Lf", &pts[i].first, &pts[i].second);
47 pts[i + N] = pts[i];
48 if(pts[i].second > topy)topy = pts[i].second, top = i;
49 }
50 for(int i = 1; i <= N; ++i)for(int j = 1; j <= N; ++j)
51 dis[i][j] = dis[i + N][j] = dis[i][j + N] = dis[i + N][j + N] = CalDis(pts[i], pts[j]);
52 dp[top][top][0] = dp[top][top][1] = dp[top + N][top + N][0] = dp[top + N][top + N][1] = 0.0;
53 for(int len = 2; len <= N; ++len)
54 for(int l = 1; l <= (N << 1) - len + 1; ++l){
55 int r = l + len - 1;
56 Update(l, r, 0, l + 1, r, 0, l + 1, l);
57 Update(l, r, 0, l + 1, r, 1, r, l);
58 Update(l, r, 1, l, r - 1, 0, l, r);
59 Update(l, r, 1, l, r - 1, 1, r - 1, r);
60 }
61 ld ansv(1e12); tuple < int, int, int > curp(0, 0, 0);
62 for(int l = 1; l < N; ++l){
63 int r = l + N - 1;
64 if(dp[l][r][0] < ansv)ansv = dp[l][r][0], curp = {l, r, 0};
65 if(dp[l][r][1] < ansv)ansv = dp[l][r][1], curp = {l, r, 1};
66 }
67 basic_string < int > rans;
68 auto [l, r, k] = curp;
69 auto lst = curp; curp = frm[l][r][k];
70 while(get < 0 >(curp)){
71 auto [l, r, k] = lst;
72 auto [cl, cr, ck] = curp;
73 if(l != cl)rans += l;
74 else rans += r;
75 lst = curp;
76 curp = frm[cl][cr][ck];
77 }rans += get < 0 >(lst);
78 for_each(rans.rbegin(), rans.rend(), [rans](auto val)->void{printf("%d%c", val > N ? val - N : val, val == *prev(rans.rend()) ? '\n' : ' ');});
79 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
80 return 0;
81}
82
83template < typename T >
84inline T read(void){
85 T ret(0);
86 int flag(1);
87 char c = getchar();
88 while(c != '-' && !isdigit(c))c = getchar();
89 if(c == '-')flag = -1, c = getchar();
90 while(isdigit(c)){
91 ret *= 10;
92 ret += int(c - '0');
93 c = getchar();
94 }
95 ret *= flag;
96 return ret;
97}
update-2023_03_06 初稿