题目描述
PYWBKTDA有一块白板,这块白板的四条边分别平行于坐标轴。我们可以假设这块白板的左下角在(x 1 ,y 1 )位置,右上角在(x 2 ,y 2 )位置。
现在有两块黑板放到白板的上面,这两块黑板的四条边也是平行于坐标轴的。我们可以设第1块黑板的左下角是(x 3 ,y 3 ),右上角在(x 4 ,y 4 )位置, 第2块黑板的左下角是(x 5 ,y 5 ),右上角在(x 6 ,y 6 )位置。
现在你的任务是来判断,我们从上往下看,是否有白板的部分区域可以被看到。所谓的白板部分区域被看到的意思是,白板上至少有一个点没有被黑板遮住。
输入
输入第一行有一个整数t,表示数据的组数。
接下来每组数据:
输入的第一行包含4个整数,分别表示x 1 ,y 1 ,x 2 ,y 2 ,即白板的左下角和右上角。
输入的第二行包含4个整数,分别表示x 3 ,y 3 ,x 4 ,y 4 ,即第1块黑板的左下角和右上角。
输入的第三行包含4个整数,分别表示x 5 ,y 5 ,x 6 ,y 6 ,即第2块黑板的左下角和右上角。
输出
输出有t行,对于每组数据,如果有部分白板可以被看到,就输出Y ES,否则就输出NO。
样例输入
3
2 2 4 4
1 1 3 5
3 1 5 5
3 3 7 5
0 0 4 6
0 0 7 4
5 2 10 5
3 1 7 6
8 1 11 7
样例输出
NO
YES
YES
第一个例子中,白板被黑板完全覆盖。
第二个例子中,部分白板可以看到。比如(6.5,4.5)这个点就可以被看到。
数据范围限制
对于50%的数据:
0 ≤ x 1 < x 2 ≤ 100,0 ≤ y 1 < y 2 ≤ 100。
0 ≤ x 3 < x 4 ≤ 100,0 ≤ y 3 < y 4 ≤ 100。
0 ≤ x 5 < x 6 ≤ 100,0 ≤ y 5 < y 6 ≤ 100。
对于100%的数据:
1 ≤ t ≤ 100。
0 ≤ x 1 < x 2 ≤ 10 6 ,0 ≤ y 1 < y 2 ≤ 10 6 。
0 ≤ x 3 < x 4 ≤ 10 6 ,0 ≤ y 3 < y 4 ≤ 10 6 。
0 ≤ x 5 < x 6 ≤ 10 6 ,0 ≤ y 5 < y 6 ≤ 10 6 。
解题思路
首先考虑50分算法:
把白板范围整个标记,然后再把两个黑板范围标记,最后查找白板范围有没有 没被黑板标记的点。很好实现但是100%的数据数组会爆。
100分算法:
离散化处理 (但是我不知道算法原理,建议百度)
离散化处理:
把三个板的x坐标和y坐标分别存入x和y数组,从小到大排序,再把坐标替换成坐标的排序结果,就是这个坐标的大小排位,这个排位和平常的考试排位一样。比如:1 2 5 5 7 的名次排序是 1 2 3 3 5
50分算法
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int sx,sy,ex,ey,x1,y1,x2,y2;
int a[1000][1000],Gun,T;
int main(){
//freopen("sheet.in","r",stdin);
//freopen("sheet.out","w",stdout);
scanf("%d",&T);
while(T-->0){
memset(a,0,sizeof(a));Gun=0;
scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
for(int i=sx;i<=ex-1;i++)//范围这里因为提目需求 面
for(int j=sy;j<=ey-1;j++)//但是给的是 点,可以-1(简单粗暴)
a[i][j]=1; //标记白板
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
for(int i=x1;i<=x2-1;i++)
for(int j=y1;j<=y2-1;j++)
a[i][j]=0; //标记黑板
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
for(int i=x1;i<=x2-1;i++)
for(int j=y1;j<=y2-1;j++)
a[i][j]=0; //标记黑板
for(int i=sx;i<=ex-1;i++)
for(int j=sy;j<=ey-1;j++)
Gun+=a[i][j];//查找白板标记
if(Gun>0)printf("YES\n");else printf("NO\n");
}
}
100分做法
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct DT{
int x,v,s;
}x[10],y[10];
int f[5][5],T,Gun,a[10][10];
bool cmp(const DT&k,const DT&l){
return (k.x<l.x);
}
bool cmp1(const DT&k,const DT&l){
return (k.x<l.x);
}
void read(){
memset(a,0,sizeof(a));Gun=0;
for(int i=1;i<=3;i++){
scanf("%d%d%d%d",&f[i][1],&f[i][2],&f[i][3],&f[i][4]);
x[i].x=f[i][1],x[i].v=1,x[i].s=i;
//.x存坐标数,用来排序;.v存这个坐标是左下x还是左下y、右上x、右上y
x[3+i].x=f[i][3],x[3+i].v=3,x[3+i].s=i;
//+3是因为要存6个,左下x存前三个,右上的x存后三个
y[i].x=f[i][2],y[i].v=2,y[i].s=i; //
y[3+i].x=f[i][4],y[3+i].v=4,y[3+i].s=i;//同上
}
}
void demo(){
x[0].x=y[0].x=-1;
for(int i=1;i<=6;i++){
if(x[i].x==x[i-1].x)f[x[i].s][x[i].v]=f[x[i-1].s][x[i-1].v];
//如果和前一个点一样,就像分数和前一个人一样,就和前一个人的名次相同
else f[x[i].s][x[i].v]=i;
//如果不一样,就和i相等
if(y[i].x==y[i-1].x)f[y[i].s][y[i].v]=f[y[i-1].s][y[i-1].v];
else f[y[i].s][y[i].v]=i;
}
}
void work(){
for(int i=f[1][1]+1;i<=f[1][3];i++)
for(int j=f[1][2]+1;j<=f[1][4];j++)
a[i][j]=1;
for(int i=f[2][1]+1;i<=f[2][3];i++)
for(int j=f[2][2]+1;j<=f[2][4];j++)
a[i][j]=0;
for(int i=f[3][1]+1;i<=f[3][3];i++)
for(int j=f[3][2]+1;j<=f[3][4];j++)
a[i][j]=0;
for(int i=f[1][1]+1;i<=f[1][3];i++)
for(int j=f[1][2]+1;j<=f[1][4];j++)
Gun+=a[i][j];
if(Gun>0)printf("YES\n");else printf("NO\n");
}
int main(){
freopen("sheet.in","r",stdin);
freopen("sheet.out","w",stdout);
scanf("%d",&T);
while(T-->0){
read();//读入,顺便预处理把坐标存起来
sort(x+1,x+6+1,cmp); //
sort(y+1,y+6+1,cmp1);//从小到大排序(我也不知道我为什么要写两个cmp)
demo();//把坐标替换
work();//50分的统计
}
}