P1325 雷达安装
传送门
思路:
采取贪心的思想。
把每个岛屿看作圆心,以雷达的范围 d 为半径,求出与 x 轴的左右两个交点,两交点所夹的区间就需要放置一个雷达,这样就把这道题转换为了区间取点问题。在枚举岛屿时,记录之前最后一个雷达安放的位置 las ,如果岛屿在这个雷达的范围内,就跳过,否则,在该岛屿所在的区间右端点放一个雷达。
为了代码比较好看,我打了一个巨大的结构体。
主函数部分:
int main() { n=T.resd();d=T.read(); for(LL i=1;i<=n;i++) { t[i].x=T.read(),t[i].y=T.read(); t[i].l=T.deal_l(t[i].x,t[i].y);//计算出区间的左端点 t[i].r=T.deal_r(t[i].x,t[i].y);//计算出区间的右端点 } sort(t+1,t+n+1,cmp);//按照区间右端点排序 las=t[1].r;ans++;//放置第一个雷达,记录位置 las for(LL i=2;i<=n;i++) { dis=T.dist(t[i].x,t[i].y,las,0);//计算岛屿与之前放置的最后一个雷达之间的距离 if(dis<=d) continue; else las=t[i].r,ans++;//若不在雷达范围内,在区间右端点放置一个雷达,更新 las。 } printf("%lld\n",ans); return 0; }
完整代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<cstdlib> #include<stack> #include<vector> #include<queue> #include<deque> #include<map> #include<set> using namespace std; #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define maxn 2001 typedef long long LL; LL n,ans; double d,las,dis; struct hh { double x,y,l,r;bool bo; inline double read() { double ls;scanf("%lf",&ls);return ls; } inline LL resd() { LL xs=0,kr=1;char ls; ls=getchar(); while(!isdigit(ls)) { if(!(ls^45)) kr=-1; ls=getchar(); } while(isdigit(ls)) { xs=(xs<<1)+(xs<<3)+(ls^48); ls=getchar(); } return xs*kr; } inline double deal_l(double a,double b) { return a-sqrt(d*d-b*b); } inline double deal_r(double a,double b) { return a+sqrt(d*d-b*b); } inline double dist(double a1,double b1,double a2,double b2) { return sqrt((a1-a2)*(a1-a2)+(b1-b2)*(b1-b2)); } }t[maxn],T; inline bool cmp(const hh&a,const hh&b) { return a.r<b.r; } int main() { n=T.resd();d=T.read(); for(LL i=1;i<=n;i++) { t[i].x=T.read(),t[i].y=T.read(); t[i].l=T.deal_l(t[i].x,t[i].y); t[i].r=T.deal_r(t[i].x,t[i].y); } sort(t+1,t+n+1,cmp); las=t[1].r;ans++; for(LL i=2;i<=n;i++) { dis=T.dist(t[i].x,t[i].y,las,0); if(dis<=d) continue; else las=t[i].r,ans++; } printf("%lld\n",ans); return 0; }