P5995 [PA2014] Lustra
提供一种极易理解的纯模拟做法。
虽然时空都不是很优秀,但是距离时空超限还绰绰有余。并且没有运用什么深奥的算法与技巧,非常适合算法初学者,并且还留有极大的优化空间。
理解题意,题目要求我们求出是否有工厂可以生产其他所有工厂的镜子,为满足这个要求,那么符合条件的工厂的 $w1,w2,h1,h2$ 一定是最小的。所以可将问题转化为求所有数据中 $w1,w2,h1,h2$ 四个数的最小值,是否在同一工厂。
- 易错点:
Q:
那么不是在输入的时候将 $w1,w2,h1,h2$ 四个数的最小值,分别记录,并且记录下它们的下标就可以了吗?这不就是在一串数中找最大、最小值的位置吗?然后,如果 $w1,w2,h1,h2$ 四个数的最小值的下标都一样,就输出 TAK 否则输出 NIE。
A:
其实不然,请看数据(在 $n=4$ 时):
1 5 2 3
2 3 2 6
1 5 1 6
1 5 1 4
$w1,w2$ 的最小值都存在于第一家工厂、第三家工厂和最后一家工厂中。但是一般性的查询 $w1,w2$ 两个数的最大、最小值的下标都会记录第一家工厂或最后一家工厂。然后程序就会发现 $h1,h2$ 两个数的最大、最小值的下标不在第一家工厂,与最后一家工厂,从而输出 NIE。但答案确是 TAK。
如何解决这种情况呢?我们可以将输入进来的 $w1,w2,h1,h2$ 四个数与前边已经计算好的 $w1,w2,h1,h2$ 的最大、最小值比较,如果等于最大、最小值,就将其加入标记数组中,代表这家工厂有可能有能力生产其他所有工厂的镜子。如果大于、小于最大、最小值,就见最大、最小值跟换,并清空标记数组。
这一部分的代码实现。
if(w1<=minw1){
if(w1==minw1) fw1[i]=1;
else {
minw1=w1;
memset(fw1,0,sizeof fw1);
fw1[i]=1;
}
}
整体代码实现:
#include<bits/stdc++.h>
using namespace std;
int T,n;
int minw1,maxw2,minh1,maxh2;
bool fw1[100001],fw2[100001],fh1[100001],fh2[100001];
int main(){
cin>>T;
while(T--){
minw1=minh1=10e9+1;
maxw2=maxh2=-1;
int a,b,c,d;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a>>b>>c>>d;
//这一部分已讲解,不再添加注释。
if(a<=minw1){
if(a==minw1) fw1[i]=1;
else {
minw1=a;
memset(fw1,0,sizeof fw1);
fw1[i]=1;
}
}
if(b>=maxw2){
if(b==maxw2) fw2[i]=1;
else {
maxw2=b;
memset(fw2,0,sizeof fw2);
fw2[i]=1;
}
}
if(c<=minh1){
if(c==minh1) fh1[i]=1;
else {
minh1=c;
memset(fh1,0,sizeof fh1);
fh1[i]=1;
}
}
if(d>=maxh2){
if(d==maxh2) fh2[i]=1;
else {
maxh2=d;
memset(fh2,0,sizeof fh2);
fh2[i]=1;
}
}
}
//遍历 n 家工厂,如果某家工厂四个数值都符合条件,输出 TAK。
bool flag=1;
for(int i=1;i<=n;i++){
if(fw1[i]&&fw2[i]&&fh1[i]&&fh2[i]){
cout<<"TAK"<<'\n';
flag=0;
break;
}
}
if(flag) cout<<"NIE"<<'\n';
memset(fh2,0,sizeof fh2);
memset(fh1,0,sizeof fh1);
memset(fw2,0,sizeof fw2);
memset(fw1,0,sizeof fw1);
}
return 0;
}

浙公网安备 33010602011771号