Computational Geometry?
Problem Description
Computational geometry is a branch of computer science devoted to the study of algorithms which can be stated in terms of geometry. It often comes up with charming shapes and ideas.
In this problem, our poor princess is trapped in a castle by some bad guys again, yeah, again. So, let’s seize the chance to be a hero.
Right now, the beautiful princess is in the original point of a Cartesian coordinate system, for simplification, the castle is treated as a coordinate system, like a common computational geometry problem.
There is a bomb which can be exploded anytime, and it locates at (Xo, Yo) in the castle. To save the princess, we need design a route for her to leave away the bomb as far as possible. But she already has a plan written on her notebook, which contains some vectors, and she insists on escaping in the vectors’ direction one by one, that is, if she is in point(0, 0), and the vector is (X, Y), she will be in point(X, Y) if she escapes in this vector.
You get her notebook now, and find princess’s plan is a not a good plan sometimes. Then you decide to help the princess to make some slight modification, you can change the order of those vectors, and/or reverse some vectors, that is, change vector (X, Y) to vector (-X, -Y).
We want to know the maximum distance to the bomb after modification.
Input
The first line contains a single integer T, indicating the number of test cases. Each test case begins with three integers N, Xo, Yo. Then N lines following, each line contains two integers, Xi and Yi, indicating a vector.
Technical Specification
- 1 <= T <= 100
- 1 <= N <= 100
- -100 <= Xi, Yi <= 100
- -10 000 <= Xo, Yo <= 10 000
Output
For each test case, output the case number first, then the distance rounded to three fractional digits.
Sample Input
3
1 1 1
1 1
2 2 3
-1 2
1 -2
3 3 0
2 3
3 2
1 -1
Sample Output
Case 1: 2.828
Case 2: 7.000
Case 3: 9.849
题意
初始位置在(0,0),在点(x0,y0)有一个炸弹,有n个向量(xi,yi),对于每个向量可以从 ( x , y ) − > ( x + x i , y + y i ) (x,y)->(x+x_i,y+y_i) (x,y)−>(x+xi,y+yi);可以任意调整向量的顺序,并且可以将(xi,yi)变为(-xi,-yi)。求n步移动完成后,最大化与炸弹的距离。
题解:
我觉得这题是贪心,可惜它不是。
可以发现的是向量的顺序并不影响最终结果,所以关键在于向量是否需要向反方向移动的问题。
设置数组
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k],代表考虑第i个向量后,横坐标为j时,最大最小的y坐标,k=0或1,分别代表最大、最小的y坐标。因为会有负的坐标,所以将所有坐标偏移(10000,10000),方便计算。然后DP就完事了。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctype.h>
#include<cstring>
#include<set>
#include<queue>
#include<stack>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef pair<int, string> P;
const int maxn = 200100;
const int mod = 1000000007;
int x[maxn], y[maxn];
int dp[120][20100][2];
double dis(int a1, int b1, int a2, int b2);
int main()
{
int t, n, i, j, x0, y0, mid = 10000;
scanf("%d", &t);
for(int z=1;z<=t;z++)
{
scanf("%d %d %d", &n, &x0, &y0);
x0+=mid, y0+=mid;
for(i=0;i<=n;i++)
memset(dp[i], -1, sizeof(dp[i]));
dp[0][mid][0] = dp[0][mid][1] = mid;
for(i=1;i<=n;i++)
scanf("%d %d", &x[i], &y[i]);
for(i=1;i<=n;i++)
for(j=0;j<=mid+mid;j++)
if(dp[i-1][j][0]>=0){
if(dp[i][j+x[i]][0] == -1){
dp[i][j+x[i]][0] = dp[i-1][j][0]+y[i];
dp[i][j+x[i]][1] = dp[i-1][j][1]+y[i];
}
else{
dp[i][j+x[i]][0] = max(dp[i][j+x[i]][0], dp[i-1][j][0]+y[i]);
dp[i][j+x[i]][1] = min(dp[i][j+x[i]][1], dp[i-1][j][1]+y[i]);
}
if(dp[i][j-x[i]][0] == -1){
dp[i][j-x[i]][0] = dp[i-1][j][0]-y[i];
dp[i][j-x[i]][1] = dp[i-1][j][1]-y[i];
}
else{
dp[i][j-x[i]][0] = max(dp[i][j-x[i]][0], dp[i-1][j][0]-y[i]);
dp[i][j-x[i]][1] = min(dp[i][j-x[i]][1], dp[i-1][j][1]-y[i]);
}
}
double ans = 0;
for(i=0;i<=mid+mid;i++){
if(dp[n][i][0] != -1)ans = max(ans, dis(x0, y0, i, dp[n][i][0]));
if(dp[n][i][1] != -1)ans = max(ans, dis(x0, y0, i, dp[n][i][1]));
}
printf("Case %d: %.3f\n", z, ans);
}
return 0;
}
double dis(int a1, int b1, int a2, int b2)
{
return sqrt((a1-a2)*(a1-a2)+(b1-b2)*(b1-b2));
}