HDOJ - 4562/西山居复赛2 守护雅典娜

     比赛的时候WA得一塌糊涂~~原因!..读题粗心了!!上一题的输出是Case #1: 0 , 而本题居然是Case 1: 1 ... 同一套题..神坑...

思路很简单了..能产生防御效果的..无非是能包住雅典娜或者包住怪兽的圆..而当一个圆同时包住了雅典娜和怪兽..同样也没有了防御效果..

考虑N个圆包住一个点并且互不相交/切能取最多圆的个数问题..用dp解决..dp顺序按照圆的半径从小到大(很明显,一个圆要包住另一个圆,其半径必须比它大)...

分别算出了包住雅典娜dp[0][],包住怪兽的dp值dp[1][]..再找两个不相冲突能得到的最大圆个数...既是答案..


Program:

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#define pi acos(-1.0)
#define ll long long
#define oo 1000000000
#define MAXN 1005
using namespace std;  
struct node
{
       int x,y,r;
}a[MAXN];
int n,x,y,sum[2][MAXN];
bool cmp(node a,node b)
{
       return a.r<b.r;
}
bool ok(node a,node b)  // 判断两个圆是否不相交/切
{
       int d,r1,r2;
       d=(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y); 
       r1=a.r-b.r;    r2=a.r+b.r;
       if (r1*r1<=d && d<=r2*r2) return false; 
       return true;
} 
int main()
{ 
       int T,t,i,j,ans; 
       scanf("%d",&T);
       for (t=1;t<=T;t++)
       {  
             scanf("%d%d%d",&n,&x,&y);
             for (i=1;i<=n;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].r);
             sort(a+1,a+1+n,cmp); 
             ans=0;
             memset(sum,0,sizeof(sum));
             for (i=1;i<=n;i++)
             {
                   if (a[i].x*a[i].x+a[i].y*a[i].y>=a[i].r*a[i].r ||
                       (a[i].x-x)*(a[i].x-x)+(a[i].y-y)*(a[i].y-y)<=a[i].r*a[i].r ) //找出包住雅典娜,但又包不住怪兽的圆
                           continue; 
                   for (j=1;j<i;j++)
                     if (sum[0][i]<sum[0][j] && ok(a[i],a[j]))
                       sum[0][i]=sum[0][j];
                   sum[0][i]++; 
                   ans=max(ans,sum[0][i]);
             } 
             for (i=1;i<=n;i++)
             {
                   if (a[i].x*a[i].x+a[i].y*a[i].y<=a[i].r*a[i].r ||
                       (a[i].x-x)*(a[i].x-x)+(a[i].y-y)*(a[i].y-y)>=a[i].r*a[i].r )  //找出包住怪兽,但又包不住雅典娜的圆
                           continue; 
                   for (j=1;j<i;j++)
                     if (sum[1][i]<sum[1][j] && ok(a[i],a[j]))
                       sum[1][i]=sum[1][j];
                   sum[1][j]++;
                   ans=max(ans,sum[1][i]);
             } 
             for (i=1;i<=n;i++)
                for (j=1;j<=n;j++)
                 if (ans<sum[0][i]+sum[1][j] && ok(a[i],a[j])) ans=sum[0][i]+sum[1][j]; // 合并两个结果
             printf("Case %d: %d\n",t,ans);
       }
       return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值