守护雅典娜 HDU-4562
vj链接:
题目描述:
许多塔防游戏都是以经典的“守护雅典娜”为原型的。玩家需要建立各种防御工具来阻止怪物接近我们的女神——雅典娜。
这里,我们可以建造的防御工具只有标准圆形状的防御墙,建立在雅典娜与怪物出生点之间的防御墙数目越多,胜利的希望就越大。这里,将问题简化到一个二维坐标系里,并且假设雅典娜的坐标为原点(0, 0),怪物出生点的坐标为(X, Y)。有N个给定圆心坐标与半径的防御墙可以供玩家选择建立,但要保证所有的圆都不发生相切或相交的情况。注意这些雅典娜位置与怪物出生点位置也不能在墙壁的边缘,即表示防御墙的圆上。点的面积与墙的厚度都很小,可以忽略不计。
记住,在游戏开始之后,怪物可以沿着任何轨迹,选择突破最少的圆形防御墙来到雅典娜的身边,而一个防御墙一旦被突破,它就会失去保护作用。所以,你的方案必须足够优秀。为了守护女神,快去找出最优的建设方案吧!
这里,我们可以建造的防御工具只有标准圆形状的防御墙,建立在雅典娜与怪物出生点之间的防御墙数目越多,胜利的希望就越大。这里,将问题简化到一个二维坐标系里,并且假设雅典娜的坐标为原点(0, 0),怪物出生点的坐标为(X, Y)。有N个给定圆心坐标与半径的防御墙可以供玩家选择建立,但要保证所有的圆都不发生相切或相交的情况。注意这些雅典娜位置与怪物出生点位置也不能在墙壁的边缘,即表示防御墙的圆上。点的面积与墙的厚度都很小,可以忽略不计。
记住,在游戏开始之后,怪物可以沿着任何轨迹,选择突破最少的圆形防御墙来到雅典娜的身边,而一个防御墙一旦被突破,它就会失去保护作用。所以,你的方案必须足够优秀。为了守护女神,快去找出最优的建设方案吧!
Input输入第一行为T,表示有T组测试数据。
每组数据以三个整数N,X,Y开始,接下去的N行每行包括三个整数Xi,Yi,Ri,表示一个可以选择的圆心为(Xi, Yi)半径为Ri的防御墙。
1. 1 <= T <= 100
2. 1 <= N <= 1000
3. 1 <= Ri <= 10 000
4. -10 000 <= X, Y, Xi, Yi <= 10 000,坐标不会相同Output对每组数据,先输出为第几组数据,然后输出能够间隔在雅典娜与怪物出生点之间最多的防御墙数目。Sample Input
3
1 5 5
1 0 2
1 5 5
1 0 9
3 5 5
1 0 2
4 5 2
2 0 6
Sample Output
Case 1: 1
Case 2: 0
Case 3: 2
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 #include<cmath>
6 using namespace std;
7 int T,N,X,Y;
8 int xx,yy,rr,k;
9 struct node{
10 int x;
11 int y;
12 int r;
13 int num;
14 }ya[1100],guai[1100];
15 int dp1[1100];
16 int dp2[1100];
17 int dp3[1100];
18 int cmp(node a,node b)
19 {
20 return a.r<b.r;
21 }
22 int judge(node a,node b)
23 {
24 int d=(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
25 if((a.r-b.r)*(a.r-b.r)<=d&&d<=(a.r+b.r)*(a.r+b.r))
26 return 0;//两圆不是相离的也不是内含的就返回0
27 else
28 return 1;
29 }
30 int main()
31 {
32 cin>>T;
33 while(T--)
34 {
35 int l1=0,l2=0;
36 memset(dp1,0,sizeof(dp1));
37 memset(dp2,0,sizeof(dp2));
38 memset(dp3,0,sizeof(dp3));
39 cin>>N>>X>>Y;
40 for(int i=1;i<=N;i++)
41 {
42 cin>>xx>>yy>>rr;
43 if((xx*xx+yy*yy<rr*rr)&&(X-xx)*(X-xx)+(Y-yy)*(Y-yy)>rr*rr)
44 {
45 //将包含怪兽的或是不包含雅典娜的排除掉
46 ya[l1].x=xx;
47 ya[l1].y=yy;
48 ya[l1].r=rr;
49 ya[l1].num=1;
50 l1++;
51 }
52 if((xx*xx+yy*yy>rr*rr)&&(X-xx)*(X-xx)+(Y-yy)*(Y-yy)<rr*rr)
53 {//将包含雅典娜的或是不包含怪兽的排除掉
54 guai[l2].x=xx;
55 guai[l2].y=yy;
56 guai[l2].r=rr;
57 guai[l2].num=1;
58 l2++;
59 }
60 }
61 sort(ya,ya+l1,cmp);
62 //以半径从小到大排序,使得相邻的两个圆便于比较
63 sort(guai,guai+l2,cmp);
64 int ans=0;
65 if(l1==1)
66 {
67 ans=max(ans,ya[0].num);
68 }
69 //对雅典娜进行动态规划
70 for(int i=1;i<l1;i++)
71 {
72 for(int j=0;j<i;j++)
73 {
74 if(judge(ya[i],ya[j]))//判断两个圆是否是内含的
75 {
76 ya[i].num=max(ya[i].num,ya[j].num+1);
77 }
78 ans=max(ans,ya[i].num);
79
80 }
81 }
82 //对怪兽进行动态规划
83 if(l2==1)
84 {
85 ans=max(ans,guai[0].num);
86 }
87 for(int i=1;i<l2;i++)
88 {
89 for(int j=0;j<i;j++)
90 {
91 if(judge(guai[i],guai[j]))
92 {
93 guai[i].num=max(guai[i].num,guai[j].num+1);
94 }
95 ans=max(ans,guai[i].num);
96 //ans代表的是只雅典娜或是只是怪兽的最大屏障数,总的只会比ans大于等于,不会小于
97 }
98 }
99 //将两者动态规划的结果合并
100 for(int i=0;i<l1;i++)
101 {
102 for(int j=0;j<l2;j++)
103 {
104 if(judge(ya[i],guai[j]))
105 {
106 ans=max(ans,ya[i].num+guai[j].num);
107 }
108 }
109 }
110 printf("Case %d: %d\n",k++,ans);
111 }
112 return 0;
113 }