列表

详情


NC22575. 艾伦的立体机动装置

描述

众所周知,立体机动装置可以用腰部的发射机射出固定器,固定在巨人身上或是建筑物上后,再利用高压瓦斯将固定器的缆绳给卷回来使身体高速移动,并通过身体的摆动利用这立体的高速机动力来战斗。也就是说它可以让人在墙壁或大地的表面运动。
现在艾伦要使用立体机动装置从多边形城墙上一个顶点运动到墙角另一个顶点,求最短距离。
给出平面上一个n个点的凸多边形,表示城墙围城的区域。
将这个多边形当成一个直棱柱的底面。
给定直棱柱的高h(表示城墙的高度,城墙厚度忽略不计)、上表面上的一个顶点s和下表面上的一个顶点t。
问在不经过直棱柱上表的情况下,沿直棱柱的表面从s走到t的最短距离。

输入描述

第一行两个整数n(),h()。
接下来n行,第i行两个实数x_iy_i(,不超过6位小数),表示第i个点的坐标。保证按逆时针顺序给出凸多边形上的点。
最后一行两个整数s,t(),表示从上底面的第s个点到下底面的第t个点(按照输入顺序从1到n给点标号)。

输出描述

一行一个实数,表示最小距离(绝对或相对误差不超过即会被判为正确)。

示例1

输入:

4 2
0 0
1 0
1 1
0 1
1 3

输出:

2.828427

示例2

输入:

4 2
0 1
0 0
3 0
3 1
1 3

输出:

4.24264

说明:

从上表面的(0, 1)从墙壁沿直线走到下表面的(2, 1),然后再由下表面的(2, 1)从下表面沿直线走到下表面的(3, 0)。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 265ms, 内存消耗: 2016K, 提交时间: 2019-10-19 15:04:58

#include<bits/stdc++.h>

typedef long long ll;
using namespace std;
const int INF = 0x3f3f3f3f;
const ll LLINF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 2e5 + 5;
const ll mod = 1e9 + 7;
const double eps = 1e-6;
int n, s, t;
double x[MAXN], y[MAXN], h;

double getdis(int i, int j) {
    return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}

double cal(double now, int nowpos, int prepos, double carry) {
    double dx = x[nowpos] - x[prepos];
    double dy = y[nowpos] - y[prepos];
    double xx = x[prepos] + dx * now;
    double yy = y[prepos] + dy * now;
    carry += getdis(nowpos, prepos) * now;
    double ans1 = sqrt(carry * carry + h * h);
    double ans2 = sqrt((xx - x[t]) * (xx - x[t]) + (yy - y[t]) * (yy - y[t]));
    return ans1 + ans2;
}

double getans(int delta) {
    double ans = h + getdis(s, t);
    double carry = 0;
    int nowpos = s;
    int prepos = s;
    do {
        prepos = nowpos;
        nowpos += delta, nowpos %= n, nowpos += n, nowpos %= n;
        double l = 0, r = 1, midl, midr;
        while (r - l > eps) {
            double delta = (r - l) / 3;
            midl = l + delta;
            midr = midl + delta;
            if (cal(midl, nowpos, prepos, carry) >= cal(midr, nowpos, prepos, carry))l = midl;
            else r = midr;
        }
        ans = min(ans, cal(l, nowpos, prepos, carry));
        carry += getdis(nowpos, prepos);
    } while (prepos != t);
    return ans;
}

int main() {
    scanf("%d%lf", &n, &h);
    for (int i = 0; i < n; i++)scanf("%lf%lf", &x[i], &y[i]);
    scanf("%d%d", &s, &t), s--, t--;
    double ans = min({getans(1), getans(-1)});
    printf("%.6f\n", ans);
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 519ms, 内存消耗: 1912K, 提交时间: 2020-03-14 16:02:11

#include<bits/stdc++.h>
using namespace std;
typedef double D;
int n,h,s,t;
D a[100007],b[100007],ans=1e18;
D dis(D x,D y,D xx,D yy)
{
	return sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));
}
void work(int ad)
{
	D len=0;
	int p=s;
	while(p!=t)
	{
		D val=dis(a[p],b[p],a[(p+ad+n)%n],b[(p+ad+n)%n]);
		for(int i=0;i<=100;++i)
		{
			D XX=a[p]+(a[(p+ad+n)%n]-a[p])*i/100;
			D YY=b[p]+(b[(p+ad+n)%n]-b[p])*i/100;
			ans=min(ans,dis(0,h,len+val*i/100,0)+dis(a[t],b[t],XX,YY));
		}
		len+=val,p=(p+ad+n)%n;
	}
}
int main()
{
	cin>>n>>h;
	for(int i=0;i<n;++i)
	cin>>a[i]>>b[i];
	cin>>s>>t,s--,t--;
	work(1),work(-1);
	cout<<ans;
}

上一题