POJ - 2932 - Coneology
题目链接http://poj.org/problem?id=2932
题意
给出n个不相交的圆,问有那些圆不被包含
题解
题目不存在圆相交,可以扫描线解。把每个圆拆成两个点,左端点和右端点,然后从左到右扫描。
扫到左端点,判断这个点代表的圆是否会被其他圆包含,如果不被包含就加入set内。判断只需在set内查找在该圆上下的两个圆进行判断即可。
扫到右端点就把set内的圆删掉。
#include<iostream>
#include<set>
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
typedef long long ll;
typedef double db;
const int N=4e4+7;
int n;
const db inf=1e30;
const db eps=1e-8;
int sign(db k){if(k>eps)return 1;if(k<-eps) return -1;return 0;}
int dcmp(db k1,db k2){return sign(k1-k2);}
struct Point{
db x,y;
Point operator - (const Point k)const{return(Point){x-k.x,y-k.y};}
Point operator + (const Point k)const{return(Point){x+k.x,y+k.y};}
db abs2(){return x*x+y*y;}
db abs(){return sqrt(abs2());}
db dis(Point k){return ((*this)-k).abs();}
void input(){scanf("%lf%lf",&x,&y);}
};
struct Circle{
Point o;db r;
bool inCircle(Circle k){
return dcmp(o.dis(k.o)+k.r,r)<=0;
}
bool operator <(const Circle k)const{return o.y<k.o.y;}
void input(){scanf("%lf",&r);o.input();}
}c[N];
struct Node{
db pos;
int id,val;
bool operator<(const Node k)const{return pos<k.pos;}
}a[N*2];
int tot;
set<Circle>st;
set<Circle>::iterator it;
bool in[N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
c[i].input();
a[++tot]=(Node){c[i].o.x-c[i].r,i,1};
a[++tot]=(Node){c[i].o.x+c[i].r,i,-1};
}
sort(a+1,a+1+tot);
int ans=0;
for(int i=1;i<=tot;i++){
int id=a[i].id;
if(a[i].val==1){
if(st.empty()){
in[id]=true;
st.insert(c[id]);
ans++;
continue;
}
it=st.lower_bound(c[id]);
Circle tmp=*it;
if(tmp.inCircle(c[id])) continue;
if(it!=st.begin()){
it--;
tmp=*it;
if(tmp.inCircle(c[id])) continue;
}
in[id]=true;
st.insert(c[id]);
ans++;
}
else{
if(in[id]) st.erase(st.find(c[id]));
}
}
printf("%d\n",ans);
for(int i=1;i<=n;i++) if(in[i]) printf("%d ",i);
}
HDU - 3511 - Prison Break
题目链接http://acm.hdu.edu.cn/showproblem.php?pid=3511
题意
给出n个不相交的圆,求出被包含的最大层数。
题解
很秀的写法。
一样的扫描线,遇到左端点,把圆拆成上下两个半圆插入set内,set内按每个半圆与扫描线相交的点排序,这样就要设一个全局变量GX表示扫描线的x坐标,然后set内的比较函数是以GX位标准的。而且set内的大小关系随着GX右移是不变的。
然后分类讨论一下插入的圆,扫描线相交的上下两点的关系即可算出答案。
#include<iostream>
#include<set>
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
typedef long long ll;
typedef double db;
const int N=2e5+7;
int n,tot;
int ans[N];
db GX;
const db inf=1e30;
const db eps=1e-8;
int sign(db k){if(k>eps)return 1;if(k<-eps) return -1;return 0;}
int dcmp(db k1,db k2){return sign(k1-k2);}
struct Point{
db x,y;
Point operator - (const Point k)const{return(Point){x-k.x,y-k.y};}
Point operator + (const Point k)const{return(Point){x+k.x,y+k.y};}
db abs2(){return x*x+y*y;}
db abs(){return sqrt(abs2());}
db dis(Point k){return ((*this)-k).abs();}
void input(){scanf("%lf%lf",&x,&y);}
};
struct Circle{
Point o;db r;
db gety(const int flag)const{return o.y+flag*sqrt(r*r-(GX-o.x)*(GX-o.x));}
void input(){o.input();scanf("%lf",&r);}
}c[N];
struct Node{
db pos;
int id,flag;
bool operator<(const Node k)const{return pos<k.pos;}
}a[N*2];
struct Nd{
int id,flag;
bool operator<(const Nd k)const{
if(id==k.id) return flag<k.flag;
return c[id].gety(flag)<c[k.id].gety(k.flag);
}
};
set<Nd>st;
set<Nd>::iterator it,jt;
int main()
{
int n;
while(scanf("%d",&n)!=EOF){
tot=0;st.clear();
for(int i=1;i<=n;i++){
c[i].input();
a[++tot]=(Node){c[i].o.x-c[i].r,i,1};
a[++tot]=(Node){c[i].o.x+c[i].r,i,-1};
}
sort(a+1,a+1+tot);
int res=1;
for(int i=1;i<=tot;i++){
int id=a[i].id;
GX=a[i].pos;
if(a[i].flag==1){
it=st.insert((Nd){id,1}).first;
jt=st.insert((Nd){id,-1}).first;
it++;
if(it==st.end()||jt==st.begin()){
ans[id]=1;
}
else{
jt--;
if(it->id==jt->id) ans[id]=ans[it->id]+1;
else ans[id]=max(ans[it->id],ans[jt->id]);
}
res=max(res,ans[id]);
}
else{
st.erase((Nd){id,1});
st.erase((Nd){id,-1});
}
}
printf("%d\n",res);
}
}
【最近圆对 / 判断圆是否相交】HDU - 3124 - Moonmist
题目链接http://acm.hdu.edu.cn/showproblem.php?pid=3124
题意
给出若干个圆,问任意两圆之间的距离最小是多少。
题解
二分答案,然后就是判断圆是否产生交。比较奇怪的做法,不敢保证正确性。
两根扫描线,一根从左到右扫左端点,一根从左到右扫右端点,左端点在set里加入圆,右端点在set里删除圆。set按照圆心的y轴排序。
每次插入判断插入的圆和两边是否产生交集;每次删除判断删除前是否会与两边的圆产生交集,删除后两边的圆是否会互相产生交集。反正多判断几次,好像一些乱七八糟的样例就能过去了…
希望有大佬给出正确解法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int N=5e4+7;
const db eps=1e-8;
const db inf=2e5;
int sign(db k){if(k>eps)return 1;if(k<-eps) return -1;return 0;}
int dcmp(db k1,db k2){return sign(k1-k2);}
int t,n;
struct Point{
db x,y;
Point operator -(const Point k)const{return (Point){x-k.x,y-k.y};}
db abs2()const{return x*x+y*y;}
db abs()const{return sqrt(abs2());}
db dis(const Point k)const{return ((*this)-k).abs();}
void input(){scanf("%lf%lf",&x,&y);}
void output(){printf("(%f,%f)\n",x,y);}
};
struct Circle{
Point o;db r;
bool operator<(const Circle k)const{return o.y<k.o.y;}
void input(){o.input();scanf("%lf",&r);}
}c[N];
struct Node{
db pos;
int id;
bool operator <(const Node k)const{return pos<k.pos;}
}a[N],b[N];
set<int>st;
set<int>::iterator it,jt;
bool jg(int id,db mid,set<int>::iterator it){
it++;
Circle tmp;
if(it!=st.end()){
tmp=c[*it];
if(dcmp(tmp.o.dis(c[id].o),mid*2+c[id].r+tmp.r)<=0) return true;
}
it--;
if(it!=st.begin()){
it--;
tmp=c[*it];
if(dcmp(tmp.o.dis(c[id].o),mid*2+c[id].r+tmp.r)<=0) return true;
}
return false;
}
bool ins(int id,db mid){
it=st.insert(id).first;
return jg(id,mid,it);
}
bool ers(int id,db mid){
jt=it=st.find(id);
if(jg(id,mid,it)) return true;
it++;
if(it!=st.end()&&jt!=st.begin()){
jt--;
Circle c1=c[*it],c2=c[*jt];
if(dcmp(c1.o.dis(c2.o),mid*2+c1.r+c2.r)<=0) return true;
}
st.erase(id);
return false;
}
bool ck(db mid){
st.clear();
int i=1,j=1;
while(i<=n&&j<=n){
if(a[i].pos-mid<=b[j].pos+mid){
if(ins(a[i++].id,mid)) return true;
}
else{
if(ers(b[j++].id,mid)) return true;
}
}
while(i<=n){
if(ins(a[i++].id,mid)) return true;
}
while(j<=n){
if(ers(b[j++].id,mid)) return true;
}
return false;
}
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
c[i].input();
}
sort(c+1,c+1+n);
for(int i=1;i<=n;i++){
a[i]=(Node){c[i].o.x-c[i].r,i};
b[i]=(Node){c[i].o.x+c[i].r,i};
}
sort(a+1,a+1+n);
sort(b+1,b+1+n);
db lo=0,hi=c[1].o.dis(c[2].o)-c[1].r-c[2].r;
while(hi-lo>eps){
db mid=(lo+hi)/2;
if(ck(mid)) hi=mid;
else lo=mid;
}
printf("%.6f\n",lo*2);
}
}