【LOJ】#2443. 「NOI2011」智能车比赛

题解

显然是个\(n^2\)的dp

我们要找每个点不穿过非赛道区域能到达哪些区域的交点

可以通过控制两条向量负责最靠下的上边界,和最靠上的下边界,检查当前点在不在这两条向量之间即可,对于每个点可以\(O(n)\)求出来哪些点是可以到达的

之后dp即可

注意判断S点所在区域的时候需要找靠后的那个区域……

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#define enter putchar('\n')
#define space putchar(' ')
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define eps 1e-7
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
	res = 0;char c = getchar();T f = 1;
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		res = res * 10 + c - '0';
		c = getchar();
	}
	res *= f;
}
template<class T>
void out(T x) {
	if(x < 0) {putchar('-');x = -x;}
	if(x >= 10) {
		out(x / 10);
	}
	putchar('0' + x % 10);
}
int N;
struct Point {
	db x,y;
	Point() {}
	Point(db _x,db _y) {
		x = _x;y = _y;
	}
	friend Point operator + (const Point &a,const Point &b) {
		return Point(a.x + b.x,a.y + b.y);
	}
	friend Point operator - (const Point &a,const Point &b) {
		return Point(a.x - b.x,a.y - b.y);
	}
	friend Point operator * (const Point &a,const db d) {
		return Point(a.x * d,a.y * d);
	}
	friend Point operator / (const Point &a,const db d) {
		return Point(a.x / d,a.y / d);
	}
	friend db operator * (const Point &a,const Point &b) {
		return a.x * b.y - a.y * b.x;
	}
}S,T,U[2005],D[2005],pos[2005][2];
db dis(Point a,Point b) {
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
db v,ans,dp[2005][2];
bool vis[2005][2];
void Init() {
	read(N);
	for(int i = 1 ; i <= N ; ++i) {
		scanf("%lf%lf%lf%lf",&D[i].x,&D[i].y,&U[i].x,&U[i].y);
	}
	scanf("%lf%lf",&S.x,&S.y);
	scanf("%lf%lf",&T.x,&T.y);
	scanf("%lf",&v);
	if(S.x > T.x) swap(S,T);
	for(int i = 2 ; i <= N ; ++i) {
		pos[i][0] = Point(D[i].x,max(D[i].y,D[i - 1].y));
		pos[i][1] = Point(D[i].x,min(U[i].y,U[i - 1].y));
	}
}
db dfs(int p,int c) {
	if(vis[p][c]) return dp[p][c];
	vis[p][c] = 1;
	Point M = pos[p][c];
	if((T.x >= D[p].x && T.x < U[p].x) || (p == N)) return dp[p][c] = dis(M,T);
	Point Up = pos[p + 1][1] - M,Dw = pos[p + 1][0] - M;
	dp[p][c] = dfs(p + 1,1) + dis(M,pos[p + 1][1]);
	dp[p][c] = min(dp[p][c],dfs(p + 1,0) + dis(M,pos[p + 1][0]));
	for(int i = p + 2; i <= N ; ++i) {
		if(D[i].x > T.x) break;
		if(Dw * (pos[i][0] - M) >= 0 && (pos[i][0] - M) * Up >= 0) {
			dp[p][c] = min(dp[p][c],dfs(i,0) + dis(M,pos[i][0]));
		}
		if(Dw * (pos[i][1] - M) >= 0 && (pos[i][1] - M) * Up >= 0) {
			dp[p][c] = min(dp[p][c],dfs(i,1) + dis(M,pos[i][1]));
		} 
		if(Dw * (pos[i][0] - M) >= 0) Dw = pos[i][0] - M;
		if((pos[i][1] - M) * Up >= 0) Up = pos[i][1] - M;
	}
	if(Dw * (T - M) >= 0 && (T - M) * Up >= 0) {
		return dp[p][c] = dis(M,T);
	}
	return dp[p][c];
}
void Solve() {
	for(int i = 1 ; i <= N ; ++i) {
		if(U[i].x <= S.x) continue;
		pos[i][0] = S;
		ans = dfs(i,0);	
		break;
	}
	if(ans == 0) ans = dis(S,T);
	printf("%.6lf\n",ans / v);
}
int main() {
#ifdef ivorysi
	freopen("f1.in","r",stdin);
#endif
	Init();
	Solve();
}

放假了真是颓啊QwQ

posted @ 2018-06-18 19:52  sigongzi  阅读(265)  评论(0编辑  收藏  举报