[U]3.1.4 Shaping Regions 递归,计算几何

一道很有意思的题目。只是今天的课程比较紧张,中午敲了下题,下午上完课后接着敲了下题。改了些bug,终于还是过了。鼓励一下~

解题思路:

题目大意是矩形覆盖问题,求最终见到的各种颜色矩形的面积。由于矩形比较多1000个而且坐标范围用点阵表示会爆空间。题中给的Hints也是含混不清。在队友提点下,终于到了解决的办法。用递归,因为题中有很明显的子问题性质,当前色块的矩形被上面的矩形覆盖之后可以分割成小矩形,再通过小矩形被更上面的矩形覆盖后进而递推。

由于没有想出用好的方法来表示矩形的碰撞情况,若用枚举的话,考虑情况太多而且代码冗余量太大。

矩形覆盖有3种情况:

1.完全不相交:

2.部分相交:

1.>1个角覆盖;

2.>2个角覆盖;

3.完全被包含(4个角覆盖):

显然枚举太麻烦!!!

考虑一般情况:


这样蓝色矩形就在黄色矩形的切割下分为4个小矩形。

把4个小矩形的坐标定义好,再进行递归。

那么其他情况怎么办呢??


同样的在这种情况下,也分为4个小矩形,明显的S1和S4是不符合条件的。

通过我们的坐标定义可以看出S1.ury<S1.lly 这样明显的翻折过来了,这样的矩形不能用。

而S4.urx<S4.llx,同样这样的矩形也不能用。

这种表达方式把所有的情况都包含在内了?还缺了一种:完全相交的情况!

通过坐标定义可以切出符合题意的矩形。将这种情况滤除掉就好了。

另外细节方面要注意的就是细心,还有就是坐标的问题。urx和ury那个点时没有实心点的。这点要好好注意。

总算是切掉了!

Code:

/*
ID:13ysen
LANG:C++
PROG:rect1
*/
#include<stdio.h>
#include<algorithm>
#define MAXR 1001
using namespace std;

struct node
{
 	   int llx,lly,urx,ury;
}rect[MAXR];

struct Color
{
 	   int color;
 	   int cnt;
}rec[MAXR];

bool cmp( Color a,Color b ){ return a.color<b.color; }

int N;

int min( int a,int b ){ return a<b?a:b; }
int max( int a,int b ){ return a>b?a:b; }

bool judge( node a )
{
 	 if( a.llx>a.urx || a.lly>a.ury )
 	 	 return false;
 	 return true;
}
void recursion( node a,int layer,int index )
{
 	 if( judge(a)==false )
 	 	 return ;
 	 bool recur=false;
 	 for( int i=layer+1;i<=N;i++ )
 	 {
	  	  if( a.llx>rect[i].urx || a.lly>rect[i].ury || a.urx<rect[i].llx || a.ury<rect[i].lly )
	 	  	   continue;
	  	  recur=true;
	  	  node s1,s2,s3,s4;
	  	  s1=s2=s3=s4=a;
	  	  s1.lly=rect[i].ury+1;
	  	  s3.ury=rect[i].lly-1;
	  	  s2.urx=rect[i].llx-1;
	  	  s4.llx=rect[i].urx+1;
	  	  s4.lly=s2.lly=max( rect[i].lly,a.lly );
	  	  s4.ury=s2.ury=min( rect[i].ury,a.ury );
	  	  recursion( s1,i,index );
	  	  recursion( s2,i,index );
	  	  recursion( s3,i,index );
	  	  recursion( s4,i,index );
	  	  break;
	 }
	 if( recur==false )
	 	 rec[index].cnt+=(a.urx-a.llx+1)*(a.ury-a.lly+1);
 	 return ;
}
int main()
{
 	freopen( "rect1.in","r",stdin );
 	freopen( "rect1.out","w",stdout );
 	int A,B;
 	scanf( "%d %d %d",&A,&B,&N );
 	
	 for( int i=0;i<=N;i++ )
	 	 rec[i].cnt=rec[i].color=0;
	
	rect[0].llx=rect[0].lly=0;
 	rect[0].urx=A-1;rect[0].ury=B-1;
 	rec[0].color=1;
 	for( int i=1;i<=N;i++ )
 	{
 		 scanf( "%d %d %d %d %d",&rect[i].llx,&rect[i].lly,&rect[i].urx,&rect[i].ury,&rec[i].color );
		 rect[i].urx-=1;
		 rect[i].ury-=1;
	}
	for( int i=0;i<=N;i++ )
		 recursion( rect[i],i,i );
	
	sort( rec,rec+N+1,cmp );
    int ans=0;
	for( int i=0;i<=N;i++ )
	{
	 	 if( rec[i].color==rec[i+1].color )
	 	 	 ans+=rec[i].cnt;
	 	 else
  		 {
			 if( rec[i].cnt+ans>0 )
	 	 	  	 printf( "%d %d\n",rec[i].color,rec[i].cnt+ans );
	 	 	 ans=0;
         }
    }
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值