好几天都没写博客了。。

这几天一直都在看关于矩形面积的并,交和周长,到现在也稍微理解了一点。。

用的都是线段树+扫描线,,

共同点都是需要用到离散化,对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;
}

现在有的还想的不是很明白,,以后有时间了再回顾下。。。

posted on 2011-04-25 20:38  奋斗青春  阅读(1996)  评论(0编辑  收藏  举报