译 by tim green
目录[隐藏] |
[编辑]描述
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 3 2 2 18 18 2 0 8 19 19 3 8 0 10 19 4
.......
[编辑]SAMPLE OUTPUT
1 91 2 84 3 187 4 38
[编辑]INPUT EXPLANATION
请注意:被(0,0)和(2,2)所描绘的是2个单位宽、2个单位高的区域
这里有一个示意图输入:
11111111111111111111 33333333443333333331 33333333443333333331 33333333443333333331 33333333443333333331 33333333443333333331 33333333443333333331 33333333443333333331 33333333443333333331 33333333443333333331 33333333443333333331 33333333443333333331 11222222442222222211 11222222442222222211 11222222442222222211 11222222442222222211 11222222442222222211 11222222442222222211 11111111441111111111 11111111441111111111
'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: wuyihao1
LANG: 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: wuyihao1
LANG: 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;
}