[矩形切割][离散化][usaco3.1.4]Shaping Regions

来源:互联网 发布:九九网络 编辑:程序博客网 时间:2024/05/08 03:14
Shaping Regions形成的区域

译 by tim green


目录

 [隐藏] 
  • 1 描述
  • 2 格式
  • 3 SAMPLE INPUT
  • 4 SAMPLE OUTPUT
  • 5 INPUT EXPLANATION
  • 6 HINTS(谨慎地使用它们!)

[编辑]描述

N个不同的颜色的不透明的长方形(1 <= N <= 1000)被放置在一张横宽为A竖长为B的白纸上。 这些长方形被放置时,保证了它们的边与白纸的边缘平行。 所有的长方形都放置在白纸内,所以我们会看到不同形状的各种颜色。 坐标系统的原点(0,0)设在这张白纸的左下角,而坐标轴则平行于边缘。

[编辑]格式

PROGRAM NAME: rect1

INPUT FORMAT:

(file rect1.in)

按顺序输入放置长方形的方法。第一行输入的是那个放在底的长方形(即白纸)。

第 1 行: A , B 和 N由空格分开 (1 <=A, B<=10,000)

第 2 到N+1行: 为五个整数 llx, lly, urx, ury, color 这是一个长方形的左下角坐标,右上角坐标(x+1,y+1)和颜色。

颜色 1和底部白纸的颜色相同。 (1 <= color <= 2500)

OUTPUT FORMAT

(file rect1.out)

输出且仅输出所有能被看到颜色,和该颜色的总面积(可以由若干个不连通的色块组成),按color增序排列。

[编辑]SAMPLE INPUT

20 20 32 2 18 18 20 8 19 19 38 0 10 19 4

.......

[编辑]SAMPLE OUTPUT

1 912 843 1874 38

[编辑]INPUT EXPLANATION

请注意:被(0,0)和(2,2)所描绘的是2个单位宽、2个单位高的区域

这里有一个示意图输入:

1111111111111111111133333333443333333331333333334433333333313333333344333333333133333333443333333331333333334433333333313333333344333333333133333333443333333331333333334433333333313333333344333333333133333333443333333331333333334433333333311122222244222222221111222222442222222211112222224422222222111122222244222222221111222222442222222211112222224422222222111111111144111111111111111111441111111111

'4'在(8,0)与(10,19)形成的是宽为2的区域,而不是3.(也就是说,4形成的区域包含(8,0)和(8,1) ,而不是(8,0)和(8,2)) 。


方法一:矩形切割


提交了两次,因为面积为零的表示不存在,不能输出。

两天尝试了自己研究矩形切割的算法而失败。


我的思路建立在线性时间解决问题上,即由上到下依次求并。

我的两种设想:

1、完全分类讨论,两个矩形有17种相对位置关系,每种位置关系切割出的矩形数目不同,显然这种方法很难实现。

2、双进程递归,两个进程交替进行,即横竖交替,显然这样的方法速度会有很大影响。


都不能实现。现在常用的方法则摒弃了线性,退而求其次,O(n^2),事实证明能过所有数据,不知为什么。。

外层循环只考虑一个矩形,被上层的所有矩形切割后的结果,并集的实现则累加切割后的小矩形即可。

这样的话,进行了几次外层循环就得到了几个矩形的并集。


用S(A)表示A的面积。则有

S(A ∩ CuB) = S(A∪B) - S(B)


/*ID: wuyihao1LANG: C++TASK: rect1*/#include <cstdio>#include <algorithm>using std::sort;int lx[10010];int rx[10010];int ly[10010];int ry[10010];int col[10010];int col2[10010];int ans[10010];int n;int rec;void rect(int i,int llx,int lly,int rrx,int rry){while (i<n+1 && (llx>rx[i]||rrx<lx[i]||lly>ry[i]||rry<ly[i])) i ++;if (i == n+1) { rec += (rrx-llx)*(rry-lly); return; }if (lx[i]>llx){rect(i+1,llx,lly,lx[i],rry);llx=lx[i];}if (rx[i]<rrx){rect(i+1,rx[i],lly,rrx,rry);rrx=rx[i];}if (ly[i]>lly){rect(i+1,llx,lly,rrx,ly[i]);}if (ry[i]<rry){rect(i+1,llx,ry[i],rrx,rry);}}int main(){freopen("rect1.in","r",stdin);freopen("rect1.out","w",stdout);scanf("%d%d%d",rx+1,ry+1,&n);lx[1] = ly[1] = 0;col2[1] = col[1] = 1;n ++;for (int i=2;i<n+1;i++){scanf("%d%d%d%d%d",lx+i,ly+i,rx+i,ry+i,col+i);col2[i] = col[i];}ans[col[n]] = rec = (ry[n]-ly[n])*(rx[n]-lx[n]);for (int i=n-1;i>0;i--){int last = rec;rect(i+1,lx[i],ly[i],rx[i],ry[i]);ans[col[i]] += rec-last;}sort(col2+1,col2+n+1);col2[0] = -0x3f3f3f3f;for (int i=1;i<n+1;i++){if (col2[i] != col2[i-1] && ans[col2[i]]>0){printf("%d %d\n",col2[i],ans[col2[i]]);}}return 0;}


方法二:离散化+倒序染色


交了两次才过。因为离散化后,横边和纵边都为2N,而不是N。

注意跳过上下或左右相等的所有情况,这样的矩形不存在。这样对速度略有优化。

/*ID: wuyihao1LANG: C++TASK: rect1*/#include <cstdio>#include <algorithm>using std::sort;int a;int b;int n;int hr[200010];int vt[200010];int lx[1010];int ly[1010];int rx[1010];int ry[1010];int col[1010];int ans[2510];int main(){freopen("rect1.in","r",stdin);freopen("rect1.out","w",stdout);scanf("%d%d%d",&a,&b,&n);for (int i=0;i<n;i++){scanf("%d%d%d%d%d",&hr[i<<1],&vt[i<<1],&hr[(i<<1)+1],&vt[(i<<1)+1],&col[i+1]);lx[i+1] = hr[i<<1];ly[i+1] = vt[i<<1];rx[i+1] = hr[(i<<1)+1];ry[i+1] = vt[(i<<1)+1];}n ++;col[0] = 1;lx[0] = 0;ly[0] = 0;rx[0] = a;ry[0] = b;hr[(n-1)<<1] = 0;vt[(n-1)<<1] = 0;hr[((n-1)<<1)+1] = a;vt[((n-1)<<1)+1] = b;sort(hr,hr+(n<<1));sort(vt,vt+(n<<1));for (int i=1;i<(n<<1);i++){if (hr[i]==hr[i-1])continue;for (int j=1;j<(n<<1);j++){if (vt[j]==vt[j-1])continue;for (int k=n-1;k>-1;k--){if (hr[i-1]>=lx[k] && hr[i]<=rx[k]&&vt[j-1]>=ly[k] && vt[j]<=ry[k]){ans[col[k]] += (hr[i]-hr[i-1])*(vt[j]-vt[j-1]);break;}}}}for (int i=1;i<2501;i++){if (ans[i])printf("%d %d\n",i,ans[i]);}return 0;}


原创粉丝点击