hdu1542 , 1255,1828矩形面积的并,交,和矩形的周长

好几天都没写博客了。。

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

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

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

}

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

你可能感兴趣的:(HDU)