第一思路比较容易想到的是使用搜索或者去模拟爆炸的过程
即将当前节点先初始化为排雷火箭,然后遍历所有还未被引爆的地雷,如果某个地雷被当前地雷引爆了,就做个标记,同时将其作为下一节点
下面是使用栈去模拟这个过程的代码,本质上与DFS大差不差
#include<iostream> #include<stack> #include<vector> #include<cmath> using namespace std; typedef struct Node{ int x,y,r; bool boom=false;//boom标志该地雷是否被引爆过(题目提到可能存在重复地雷 }Node; vector<Node>v;//存储地雷 int n,m,ans=0; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ int x,y,r; cin>>x>>y>>r; Node node; node.x=x;node.y=y;node.r=r; v.push_back(node);//存地雷 } while(m--){ int x,y,r,len=v.size(); cin>>x>>y>>r; stack<Node>stk; Node node;node.x=x;node.y=y;node.r=r; stk.push(node); while(!stk.empty()){ Node now=stk.top();//当前地雷 stk.pop(); for(int i=0;i<len;i++){//遍历所有地雷 Node temp=v[i]; if(temp.boom)continue;//如果该地雷已经引爆过就跳过 double dis=sqrt((now.x-temp.x)*(now.x-temp.x)+(now.y-temp.y)*(now.y-temp.y)); if(dis<=now.r){//距离合适 v[i].boom=true;//标记 stk.push(temp);//作为下一个地雷 ans++; } } } } cout<<ans<<endl; return 0; }
但是该方法时间复杂度为O(mn)只能拿到40分
实际上,通过观察数据范围我们不难得知的是,爆炸的范围可能要远远小于炸弹之间的距离,按照上面的代码所写的话,我们遍历了所有的炸弹,实际上可以不用遍历那么多,只选择遍历在当前炸弹附近的即可,因此,这里我们选择以x轴上的距离为标准,将遍历的炸弹范围缩小至只在(x-r,x+r)之间的炸弹(读者可自行画图理解)
据此,我们先对所有的炸弹按照x的大小从小到大进行排序,然后找到最接近x-r距离的炸弹下标和最接近x+r的炸弹下标,然后只对他们之间炸弹的进行遍历即可
#include<bits/stdc++.h> using namespace std; long long n,m,ans; double dis(double x1,double y1,double x2,double y2){ return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } struct zhalei{ long long x,y,r; bool flag=0; }a[50005]; struct pailei{ long long x,y,r; }b[50005];//这个结构体是排雷火箭,按顺序引爆时不需要 flag bool cmp(zhalei a,zhalei b){ return a.x<b.x; } void dfs(int x,int y,int r){ int Lmid,Rmid,L=1,R=n; while(L<=R){ Lmid=(L+R)/2; if(a[Lmid].x<x-r)L=Lmid+1; else R=Lmid-1; } Lmid=L; L=1,R=n; while(L<=R){ Rmid=(L+R)/2; if(a[Rmid].x<=x+r)L=Rmid+1; else R=Rmid-1; } for(long long i=Lmid;i<=Rmid;i++){ if(!a[i].flag&&dis(x,y,a[i].x,a[i].y)<=r){ a[i].flag=1,ans++; dfs(a[i].x,a[i].y,a[i].r); } } } int main(){ long long i; scanf("%lld%lld",&n,&m); for(i=1;i<=n;i++)scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].r); for(i=1;i<=m;i++)scanf("%lld%lld%lld",&b[i].x,&b[i].y,&b[i].r); sort(a+1,a+n+1,cmp); for(i=1;i<=m&&ans<n;i++)//依次引爆排雷火箭 dfs(b[i].x,b[i].y,b[i].r);//小优化,已引爆的炸弹数<n时 printf("%lld",ans); return 0; }