vj链接:

守护雅典娜


题目描述:

许多塔防游戏都是以经典的“守护雅典娜”为原型的。玩家需要建立各种防御工具来阻止怪物接近我们的女神——雅典娜。 

这里,我们可以建造的防御工具只有标准圆形状的防御墙,建立在雅典娜与怪物出生点之间的防御墙数目越多,胜利的希望就越大。这里,将问题简化到一个二维坐标系里,并且假设雅典娜的坐标为原点(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 }