好几天都没写博客了。。
这几天一直都在看关于矩形面积的并,交和周长,到现在也稍微理解了一点。。
用的都是线段树+扫描线,,
共同点都是需要用到离散化,对y坐标进行从小到大排序,除去相等的y点,根据y轴进行建树。。
然后扫描线需要记录是矩形的左边界还是右边界。。。
每一个结点的c表示该线段被覆盖的次数,具体看代码:
矩形面积的并:
# include<stdio.h>
# include<stdlib.h>
# define N 210
struct node{
double x,y1,y2;
int f;
}Line[N];
struct node1{
double lf,rf,cnt;
int l,r,c;
}tree[N*3];
double y[N];
int cmp(const void *a,const void *b)
{
struct node * c = (struct node *)a;
struct node * d = (struct node *)b;
return c->x > d->x ?1:-1;
}
int cmp1(const void *a,const void *b)
{
return *(double *)a > *(double *)b ? 1:-1;
}
void bulid(int t,int l,int r)
{
int mid;
tree[t].c=0;tree[t].cnt=0;
tree[t].l=l;
tree[t].r=r;
tree[t].lf=y[l];
tree[t].rf=y[r];
if(l+1==r) return;
mid=(l+r)/2;
bulid(2*t,l,mid);
bulid(2*t+1,mid,r);
}
void calen(int t)
{
if(tree[t].c>0)
{
tree[t].cnt=tree[t].rf-tree[t].lf;
return ;
}
if(tree[t].l+1==tree[t].r) tree[t].cnt=0;
else tree[t].cnt=tree[2*t].cnt+tree[2*t+1].cnt;
}
void updata(int t,node e)
{
if(e.y1 == tree[t].lf && e.y2==tree[t].rf)
{
tree[t].c+=e.f;
calen(t);
return;
}
if(e.y2 <=tree[2*t].rf ) updata(2*t,e);
else if(e.y1 >=tree[2*t+1].lf) updata(2*t+1,e);
else
{
node tmp=e;
tmp.y2=tree[2*t].rf;
updata(2*t,tmp);
tmp=e;
tmp.y1=tree[2*t+1].lf;
updata(2*t+1,tmp);
}
calen(t);
}
int main()
{
int i,n,ncase=0,t;
double x1,y1,x2,y2,ans;
while(scanf("%d",&n)!=EOF && n)
{
ncase++;
t=1;
for(i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
Line[t].x=x1;
Line[t].y1=y1;
Line[t].y2=y2;
Line[t].f=1;
y[t]=y1;
Line[t+1].x=x2;
Line[t+1].y1=y1;
Line[t+1].y2=y2;
Line[t+1].f=-1;
y[t+1]=y2;
t+=2;
}
qsort(Line+1,t-1,sizeof(Line[1]),cmp);
qsort(y+1,t-1,sizeof(y[1]),cmp1);
bulid(1,1,t-1);
ans=0;
for(i=1;i<t;i++)
{
ans+=tree[1].cnt*(Line[i].x - Line[i-1].x);
updata(1,Line[i]);
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n",ncase,ans);
}
return 0;
}
再介绍一种求矩形面积并的方法,离散。。
对x,y分别离散,最后转化为(2n-1)*(2n-1)个小矩形(n表示矩形的个数),,对于n比较小的情况,这样也可以求矩形的交,甚至矩形的并。。
大致意思就是,每询问一个矩形,记录其左下角的顶点坐标和右上角的顶点坐标,用二分或者hash找出 所对应的下表,然后把这两个顶点之间所有的小矩形
都标记一下,最后再遍历一遍,对于被标记的小矩形,sum加上其面积,ok。。
代码:
# include<stdio.h>
# include<string.h>
# include<stdlib.h>
struct node{
double x1,y1,x2,y2;
}s[105];
double y[205],x[205];
int visit[205][205],xs,ys;
int cmp(const void *a, const void *b)
{
return *(double *)a > *(double *)b ? 1 : -1;
}
int find1(double ch)
{//一定会找到
int left,right,mid;
left=1;
right=xs;
while(right>=left)
{
mid=(right+left)/2;
if(x[mid]==ch) return mid;
else if(x[mid]>ch) right=mid-1;
else left=mid+1;
}
}
int find2(double ch)
{//一定会找到
int left,right,mid;
left=1;
right=ys;
while(right>=left)
{
mid=(right+left)/2;
if(y[mid]==ch) return mid;
else if(y[mid]>ch) right=mid-1;
else left=mid+1;
}
}
int main()
{
int i,j,k,x11,y11,x22,y22,ncase=0,t,n;
double ans;
while(scanf("%d",&n)!=EOF)
{
ncase++;
if(n==0) break;
t=0;
for(i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&s[i].x1,&s[i].y1,&s[i].x2,&s[i].y2);
t++;
y[t]=s[i].y1;
x[t]=s[i].x1;
t++;
y[t]=s[i].y2;
x[t]=s[i].x2;
}
qsort(y+1,t,sizeof(y[1]),cmp);
qsort(x+1,t,sizeof(x[1]),cmp);
ys=1;
for(i=2;i<=t;i++)
if(y[i]!=y[i-1]) {ys++;y[ys]=y[i];}
xs=1;
for(i=2;i<=t;i++)
if(x[i]!=x[i-1]) {xs++;x[xs]=x[i];}
memset(visit,0,sizeof(visit));
for(i=1;i<=n;i++)
{
x11=find1(s[i].x1);
x22=find1(s[i].x2);
y11=find2(s[i].y1);
y22=find2(s[i].y2);
for(j=x11;j<x22;j++)
for(k=y11;k<y22;k++)
visit[j][k]=1;
}
ans=0;
for(i=1;i<xs;i++)
for(j=1;j<ys;j++)
if(visit[i][j]==1)
{
ans+=(x[i+1]-x[i])*(y[j+1]-y[j]);
}
printf("Test case #%d\n",ncase);
printf("Total explored area: %.2lf\n\n",ans);
}
return 0;
}
矩形面积的交:
//这个比矩形面积的并多了一个incalen函数,因为只有该线段被覆盖的至少两次 所围成的面积才是相交的。,,
# include<stdio.h>
# include<stdlib.h>
# define N 1010
struct node1{
double x,y1,y2;
int f;
}line[N*2];
struct node2{
double rf,lf,cnt,incnt;
int l,r,c;
}tree[N*5];
double y[N*2];
int cmp1(const void *a,const void *b)
{
struct node1 *c=(struct node1*)a;
struct node1 *d=(struct node1*)b;
if(c->x == d->x) return c->f - d->f;
return c->x > d->x ? 1 : -1;
}
int cmp2(const void *a,const void *b)
{
return *(double *)a > *(double *)b ? 1 : -1;
}
void bulid(int t,int l,int r)
{
int mid;
tree[t].c=0;
tree[t].cnt=0;
tree[t].incnt=0;
tree[t].l=l;
tree[t].r=r;
tree[t].lf=y[l];
tree[t].rf=y[r];
if(l+1==r) return;
mid=(l+r)/2;
bulid(2*t,l,mid);
bulid(2*t+1,mid,r);
}
void calen(int t)
{
if(tree[t].c>0)
{
tree[t].cnt=tree[t].rf-tree[t].lf;
return ;
}
if(tree[t].l+1==tree[t].r) tree[t].cnt=0;
else tree[t].cnt=tree[2*t].cnt+tree[2*t+1].cnt;
}
void incalen(int t)
{
if(tree[t].c>=2)
{
tree[t].incnt=tree[t].rf-tree[t].lf;
return;
}
if(tree[t].l+1==tree[t].r) tree[t].incnt=0;
else if(tree[t].c==1)
{
tree[t].incnt=tree[2*t].cnt+tree[2*t+1].cnt;
}
else tree[t].incnt=tree[2*t].incnt+tree[2*t+1].incnt;
}
void updata(int t,node1 e)
{
node1 tmp;
if(e.y1==tree[t].lf && e.y2==tree[t].rf)
{
tree[t].c+=e.f;
calen(t);
incalen(t);
return;
}
if(e.y2<=tree[2*t].rf) updata(2*t,e);
else if(e.y1>=tree[2*t+1].lf) updata(2*t+1,e);
else
{
tmp=e;
tmp.y2=tree[2*t].rf;
updata(2*t,tmp);
tmp=e;
tmp.y1=tree[2*t+1].lf;
updata(2*t+1,tmp);
}
calen(t);
incalen(t);
}
int main()
{
int i,ncase,n,t;
double x1,x2,y1,y2,ans;
scanf("%d",&ncase);
while(ncase--)
{
scanf("%d",&n);
t=1;
for(i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
line[t].x=x1;
line[t].y1=y1;
line[t].y2=y2;
line[t].f=1;
y[t]=y1;
line[t+1].x=x2;
line[t+1].y1=y1;
line[t+1].y2=y2;
line[t+1].f=-1;
y[t+1]=y2;
t+=2;
}
qsort(line+1,t-1,sizeof(line[1]),cmp1);
qsort(y+1,t-1,sizeof(y[1]),cmp2);
bulid(1,1,t-1);
ans=0;
for(i=1;i<t;i++)
{
ans+=tree[1].incnt*(line[i].x - line[i-1].x);
updata(1,line[i]);
}
printf("%.2lf\n",ans);
}
return 0;
}
矩形的周长:
//我感觉这个不太好理解,,和矩形面积的并有点的相似,不过需要在结点里面加好多的域进行判断。。
# include<stdio.h>
# include<stdlib.h>
# include<math.h>
# define N 5005
struct node1{
int x,y1,y2;
int f;
}line[2*N];
struct node2{
int l,r;
int lf,rf;/*左右区间所对应的y值*/
int cnt;/*节点上线段的测度*/
int count;/*节点被线段完全覆盖的次数*/
int lines;/*节点上所包含的线段的段数*/
int lb,rb;/*节点的左右端点是否被覆盖*/
}tree[4*N];
int y[2*N];
int cmp1(const void *a,const void *b)
{
struct node1*c=(struct node1 *)a;
struct node1*d=(struct node1 *)b;
if(c->x!=d->x) return c->x - d->x;
return d->f - c->f;/*先入 再出*/
}
int cmp2(const void *a,const void *b)
{
return *(int *)a - *(int *)b;
}
void bulid(int t,int l,int r)
{
int mid;
tree[t].lines=0;
tree[t].cnt=0;
tree[t].count=0;
tree[t].lb=tree[t].rb=0;
tree[t].l=l;
tree[t].r=r;
tree[t].lf=y[l];
tree[t].rf=y[r];
if(l+1==r) return;
mid=(l+r)/2;
bulid(2*t,l,mid);
bulid(2*t+1,mid,r);
}
void calen(int t)
{
if(tree[t].count>0)
{
tree[t].cnt=tree[t].rf-tree[t].lf;
tree[t].lines=1;
return;
}
if(tree[t].l+1==tree[t].r)
{
tree[t].cnt=0;
tree[t].lines=0;
}
else
{
tree[t].cnt=tree[2*t].cnt+tree[2*t+1].cnt;
tree[t].lines=tree[2*t].lines+tree[2*t+1].lines;
if(tree[2*t].rb!=0&&tree[2*t+1].lb!=0) tree[t].lines--;
}
}
void updata(int t,node1 e)
{
node1 tmp;
if(tree[t].lf==e.y1) tree[t].lb+=e.f;
if(tree[t].rf==e.y2) tree[t].rb+=e.f;
if(tree[t].lf==e.y1 && tree[t].rf==e.y2) tree[t].count+=e.f;
else if(e.y2<=tree[2*t].rf) updata(2*t,e);
else if(e.y1>=tree[2*t+1].lf) updata(2*t+1,e);
else
{
tmp=e;
tmp.y2=tree[2*t].rf;
updata(2*t,tmp);
tmp=e;
tmp.y1=tree[2*t+1].lf;
updata(2*t+1,tmp);
}
calen(t);
}
int main()
{
int i,n,ys,ans,x1,x2,y1,y2,lastlen,t,lines;
while(scanf("%d",&n),n)
{
t=1;
for(i=1;i<=n;i++)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
line[t].x=x1;
line[t].y1=y1;
line[t].y2=y2;
line[t].f=1;
y[t]=y1;
line[t+1].x=x2;
line[t+1].y1=y1;
line[t+1].y2=y2;
line[t+1].f=-1;
y[t+1]=y2;
t+=2;
}
qsort(line+1,t-1,sizeof(line[1]),cmp1);
qsort(y+1,t-1,sizeof(y[1]),cmp2);
ys=2;
for(i=2;i<t;i++)
{
if(y[i]!=y[i-1]) {y[ys]=y[i];ys++;}
}/*去除y坐标相同的*/
bulid(1,1,ys-1);
ans=0;
lastlen=0;
lines=0;
for(i=1;i<t;i++)
{
updata(1,line[i]);
if(i!=1) ans+=lines*(line[i].x - line[i-1].x)*2;
ans+=abs(lastlen - tree[1].cnt);
lastlen=tree[1].cnt;
lines=tree[1].lines;
}
printf("%d\n",ans);
}
return 0;
}
现在有的还想的不是很明白,,以后有时间了再回顾下。。。
浙公网安备 33010602011771号