这是本蒟蒻第一次写题解,各位大佬看了勿喷。
拿到题目第一反应是什么?开个数组模拟白纸,将“纸”初始化为
1
1
1,再根据题目要求一步一步来,将长方形覆盖到纸上(类似于染色),n步染完后可以再统计。似乎没什么问题。
试一试吧:
#include<bits/stdc++.h>
using namespace std;
const int twx=1000+100;
const int tt=10000+100;
const int nx=2500+100;
int y[tt][tt]={};
int a,b,n;
int orz[nx]={};
struct LV
{
int llx,lly,urx,ury,color;
}tw[twx];
void init()
{
cin>>a>>b>>n;
for(int i=1;i<=n;i++)
{
cin>>tw[i].llx>>tw[i].lly>>tw[i].urx>>tw[i].ury>>tw[i].color;
}
}
void work()
{
for(int i=0;i<a;i++)
{
for(int j=0;j<b;j++)
{
y[i][j]=1;
}
}//初始化为1
for(int i=1;i<=n;i++)
{
for(int j=tw[i].llx;j<=tw[i].urx-1;j++)
{
for(int k=tw[i].lly;k<=tw[i].ury-1;k++)
{
y[j][k]=tw[i].color;
}
}
}//覆盖长方形
for(int i=0;i<a;i++)
{
for(int j=0;j<b;j++)
{
orz[y[i][j]]++;
}
}//数格子
}
void print()
{
for(int i=1;i<=2500+10;i++)
{
if(orz[i]>0)
{
cout<<i<<" "<<orz[i]<<endl;
}
}
}
int main()
{
init();
work();
print();
return 0;
}
很棒,过样例了。交个看看……
结果呢。。。。。。:
90分!!!!
最后一个点超时了,仔细一看,最后那个点的数据十分强壮
问题出在哪,分析一下:
10000
∗
10000
10000*10000
10000∗10000一亿个点,单就第一次染成
1
1
1就超时了,如果数据量达到
a
10000
a10000
a10000,
b
10000
b10000
b10000,
n
1000
n1000
n1000,并且后面所有点都是完全覆盖,那得
1000
1000
1000多秒的时间。估计没哪个算法竞赛会给那么长的时间。
对于此类极端数据,唯一的办法就是:修改算法,拒绝暴力。
网上有位大佬给了一个方法:线段分割。
一个图中,已有矩形
(
x
1
,
y
1
,
x
2
,
y
2
)
(x1,y1,x2,y2)
(x1,y1,x2,y2)现插入一个矩形
(
x
3
,
y
3
,
x
4
,
y
4
)
(x3,y3,x4,y4)
(x3,y3,x4,y4)开始对
(
x
1
,
y
1
,
x
2
,
y
2
)
(x1,y1,x2,y2)
(x1,y1,x2,y2)进行切割
第一步:在x方向上切割,将线段
(
x
1
,
x
2
)
(x1,x2)
(x1,x2)割成
(
x
1
,
x
3
)
(x1,x3)
(x1,x3)和
(
x
4
,
x
2
)
(x4,x2)
(x4,x2)两条,因此我们得到了两个矩形
(
x
1
,
y
1
,
x
3
,
y
2
)
(x1,y1,x3,y2)
(x1,y1,x3,y2)和
(
x
4
,
y
1
,
x
2
,
y
2
)
(x4,y1,x2,y2)
(x4,y1,x2,y2)将这两个矩放入矩形集合,去掉后后得到了矩形
(
x
3
,
y
1
,
x
4
,
y
4
)
(x3,y1,x4,y4)
(x3,y1,x4,y4)。
第二步:再在y方向上切割,将线段(y1,y2)割成(y1,y3)和(y2,y3)两条
因此我们得到了个矩形(x3,y1,x4,y2)。将其放入矩形集合。
第三步:剩下了个矩形
(
x
3
,
y
3
,
x
4
,
y
2
)
(x3,y3,x4,y2)
(x3,y3,x4,y2),此矩形与矩形
(
x
3
,
y
3
,
x
4
,
y
4
)
(x3,y3,x4,y4)
(x3,y3,x4,y4)重合,所以将其删掉。
最后我们得到了:
- 将矩形在x方向上的投影进行切割,取
(
x
1
,
x
2
)
(x1,x2)
(x1,x2)和
(
x
3
,
x
4
)
(x3,x4)
(x3,x4)的交集
(
k
1
,
k
2
)
(k1,k2)
(k1,k2)
若 x 1 < k 1 x1<k1 x1<k1,就加入矩形 ( x 1 , y 1 , k 1 , y 2 ) (x1,y1,k1,y2) (x1,y1,k1,y2)
若 k 2 < x 2 k2<x2 k2<x2,就加入矩形 ( k 2 , y 1 , x 2 , y 2 ) (k2,y1,x2,y2) (k2,y1,x2,y2) - 再将矩形在y方向上的投影进行切割,取(y1,y2)和(y3,y4)的交集(k3,k4)
若 y 1 < k 3 y1<k3 y1<k3,就加入矩形 ( k 1 , y 1 , k 2 , k 3 ) (k1,y1,k2,k3) (k1,y1,k2,k3)
若 k 4 < y 2 k4<y2 k4<y2,就加入矩形 ( k 1 , k 4 , k 2 , y 2 ) (k1,k4,k2,y2) (k1,k4,k2,y2) - 将矩形
(
x
1
,
y
1
,
x
2
,
y
2
)
(x1,y1,x2,y2)
(x1,y1,x2,y2)从矩形集合中删去
(我们所做的就是求出被 ( x 3 , y 3 , x 4 , y 4 ) (x3,y3,x4,y4) (x3,y3,x4,y4)覆盖后, ( x 1 , y 1 , x 2 , y 2 ) (x1,y1,x2,y2) (x1,y1,x2,y2)所剩下的部分)
到这里我们应该已经有一个十分清晰的思路了,剩下的就是代码实现了。
#include<bits/stdc++.h>
using namespace std;
const int twx=1000+100;
const int nx=2500+100;
int space;
int a,b,n;
int orz[nx]={0};
struct LV
{
int llx,lly,urx,ury,color;
}tw[twx];
void work(int lx,int ly,int ux,int uy,int t)
{
if(t==0)
{
return ;
}
if(tw[t].llx>=ux||tw[t].lly>=uy||tw[t].urx<=lx||tw[t].ury<=ly)
{
work(lx,ly,ux,uy,t-1);
}
else
{
int k1,k2,k3,k4;
k1=max(lx,tw[t].llx);
k2=min(ux,tw[t].urx);
if(lx<k1)
{
work(lx,ly,k1,uy,t-1);
}
if(ux>k2)
{
work(k2,ly,ux,uy,t-1);
}
k3=max(ly,tw[t].lly);
k4=min(uy,tw[t].ury);
if(ly<k3)
{
work(k1,ly,k2,k3,t-1);
}
if(uy>k4)
{
work(k1,k4,k2,uy,t-1);
}
orz[tw[t].color]+=abs(k2-k1)*abs(k4-k3);
space-=abs(k2-k1)*abs(k4-k3);
}
}
void init()
{
cin>>a>>b>>n;
for(int i=1;i<=n;i++)
{
cin>>tw[i].llx>>tw[i].lly>>tw[i].urx>>tw[i].ury>>tw[i].color;
}
}
void print()
{
space=a*b;
work(0,0,a,b,n);
orz[1]+=space;
for(int i=1;i<=nx-1;i++)
{
if(orz[i]>0)
{
cout<<i<<" "<<orz[i]<<endl;
}
}
}
int main()
{
init();
print();
return 0;
}
成功AC做完这道题,感触颇深,一些题目,能优化就尽量优化,如果真想不出来解法就暴力。暴力虽简单,但效率不一定高,遇到一些极端的数据,暴力差不多是遇一个挂一个。