您的位置:首页 > 其它

【HDU5928 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 G】【计算几何 凸包思想 枚举底点做DP】Birthday Gift 给定绳长最多围住多少个点

2016-10-08 16:41 483 查看

Birthday Gift

Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 118    Accepted Submission(s): 24


[align=left]Problem Description[/align]
Both Mr. Frog and Wallice love running. Wallice missed Mr. Frog’s birthday recently,so he decided to give a belated birthday gift. He quickly found out an idea: he decided to run a closed curve to contain those meaningful
buildings. Unfortunately, he only gets a little time left since he is going to attend an important press conference.

Wallice wants to know the maximal number of buildings can be contained in the closed curve. Note that his speed is 1.

 

[align=left]Input[/align]
The first line contains only one integer T,which indicates the number of test cases.

For each test case, the first line contains an integer N (1≤N≤80),
and a double t (0≤l≤5000)
indicating the numbers of buildings Wallice cares about and the time he has.

In the following n lines, the i-th line contains two doubles xi,yi(−600≤xi,yi≤600)
indicating the position of the buildings.

 

[align=left]Output[/align]
For each test case,output one line “Case #x: ans’’,where x is the case number (starting from 1) following with ans indicating the maximum number of buildings Wallice can circled in in limited time.
 

[align=left]Sample Input[/align]

2
4 4.1
0 0
0 1
1 0
1 1
4 3.5
0 0
0 1
1 0
1 1

 

[align=left]Sample Output[/align]

Case #1: 4
Case #2: 3
Hint
For the second sample, Wallice does not have enough time to circle all the four buildings so he circles three of them instead.

It is guaranteed that the answer would not change even if l changes up to 10^-5, and there would not be any 3 points on one line even if any point changes its position up to 10^-5.

 

[align=left]Source[/align]
2016CCPC东北地区大学生程序设计竞赛
- 重现赛

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n; double L;
struct P
{
double x, y;
bool operator < (const P b)const
{
return (x * b.y - y * b.x > 0); //按照斜率从小到大排序
}
P operator - (const P b)const
{
return {x - b.x, y - b.y };
}
}p[100], q[100];
double K(double x) { return x*x; }
double DIS(P a)
{
return sqrt(a.x*a.x + a.y*a.y);
}
double f[100][100];	//f[i][j]表示以st为底端点时,以i为逆时针方向上的最后一个点,恰好包住st~i范围内的j个点的最小绳长
int main()
{
scanf("%d", &casenum);
for (casei = 1; casei <= casenum; ++casei)
{
scanf("%d%lf", &n, &L);
for (int i = 1; i <= n; ++i)scanf("%lf%lf", &p[i].x, &p[i].y);
int ans = 1;
for (int st = 1; st <= n; ++st)
{
int g = 0;
for (int i = 1; i <= n; ++i)
{
if (i != st && p[i].y >= p[st].y)q[++g] = p[i] - p[st];
}sort(q + 1, q + g + 1);

MS(f, 127); double inf = f[0][0];
for (int i = 1; i <= g; ++i)
{
f[i][2] = DIS(q[i]);
for (int j = i + 1; j <= g; ++j)
{
double link = DIS(q[j] - q[i]); if (f[i][2] + link > L)continue;
int cnt = 1;
for (int k = i + 1; k < j; ++k)
{
//查看k是否能被i-j包住,其实这里应该是 <= ,但是因为不存在三点共线,所以可以用 <
if (q[j] - q[i] < q[k] - q[i])++cnt;
}
//for (int k = 2; f[i][k] != inf; ++k)//另一种写法
for (int k = 2; k <= i + 1 && k + cnt <= j + 1; ++k)
{
double tmp = f[i][k] + link;
if(tmp <= L)gmin(f[j][k + cnt], tmp);
}
}
for (int k = 2; k <= n; ++k)if (f[i][k] + DIS(q[i]) <= L)gmax(ans, k);
}
}
printf("Case #%d: %d\n", casei, ans);
}
return 0;
}
/*
【trick&&吐槽】
这里需要注意的是,
1,从最后一个点回到st的距离不能记在f中,因为该距离是可能变小的。
2,不存在三点共线大大简化了问题,否则极角排序在斜率一致的情况下,还要按照距离从近到远做排序

【题意】
有n(80)个点,范围在[-600,600]
有长度为l(0~5000,double类型)的绳子
问你我们用这个绳子最多能围住多少个点(围成凸包围住)
数据保证不会存在三点共线

【类型】
计算几何

【分析】
这是计算几何,不过也在计算几何的基础上加了DP
我们可以枚举最低点st,按照关于st的极角排序(其实就是斜率排序啦,使得所有点都逆时针排列),存在q[]中
然后用f[i][j]表示以st为底端点时,以i为逆时针方向上的最后一个点,恰好包住st~i范围内的j个点的最小绳长

首先f[i][2]=DIS(q[i])
然后考虑转移
首先枚举转移前的节点i
然后枚举转移后的节点j
然后我们要看i到j的连线可以使得我们包含多少[i+1,j]之间的点,记做cnt

接下来就做转移
gmin(f[j][num + cnt],f[i][num] + DIS(q[i],q[j])
然后在f[i][k]+dis(q[i])<=L的条件下更新答案就好啦!

【时间复杂度&&优化】
O(n ^ 4)

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐