题意较长,注意好好理解再动手,首先可以简单概括一下题意就是给你一个大小一定的子数组,去匹配一个大数组中有多少个匹配的,匹配条件如下
此外需要强调的是这句话:特别地,藏宝图左下角位置一定是一棵树
第一思路:
第一想法是想创建两个数组来存储两张图,然后,遍历“绿化图”中每一个点作为起点(这里我当时没注意到“藏宝图左下角位置一定是一棵树”,实际上只需遍历为1的点作为左下角即可),然后遍历藏宝图,将藏宝图中的坐标与绿化图中的坐标相互转换,即藏宝图中的点(p,q),对应绿化图中的点(i+p,j+q)其中(i,j)为绿化图中的左下角的点,匹配的过程中如果发现不匹配就break,如果完美匹配就ans++即可
这里还要强调的点是
这句话,表明我们在输入数组时需要将上下进行颠倒过来
#include<iostream> using namespace std; int n,L,S,ans=0; //int index1[2005]; //int index2[2005]; int mapp1[2005][2005]; int mapp2[55][55]; int main(){ cin>>n>>L>>S; for(int i=0;i<n;i++){ int v,w; cin>>v>>w; mapp1[v][w]=1; } for(int i=S;i>=0;i--){ for(int j=0;j<=S;j++){ cin>>mapp2[i][j]; } } for(int i=0;i<=L-S;i++){ for(int j=0;j<=L-S;j++){//枚举每一个点作为藏宝图的左下角 int sign=0;//判断是否可能有宝藏 for(int p=0;p<=S;p++){//遍历以(i,j)为左下角的藏宝图与绿化图 for(int q=0;q<=S;q++){ if(mapp1[i+p][j+q]!=mapp2[p][q]){ sign=1; break; } } if(sign){ break; } } if(!sign){ ans++; } } } cout<<ans<<endl; return 0; }
因为这里为绿化图也建立了一个数组,所以最多只能拿到70分
后面仔细思考后的思路更清晰一些
首先,上面的思路选择在一开始就不正确,我们不应该也不必要为绿化图建立数组,因为遍历左下角的点只需遍历值为1的点即可,而这在输入中已经知道了,因此只需O(n)遍历即可,此外,我们还要保证选择的点作为左下角之后能否在右上角容纳下宝藏图,如果不能,则continue,反之则需要对两张图进行匹配,这里匹配两个数组对应的点是否相等,我们只需判断绿化图中的点是否在index数组中,如果在就相当于判断藏宝图中的点是否为1即可,不在index数组中则同理判断藏宝图中的点是否为0即可
#include<iostream> using namespace std; int n,L,S,ans=0; int index1[1005]; int index2[1005]; int mapp2[55][55]; bool check(int x1,int y1,int x2,int y2){ //检查(x1,x2)与(x2,y2)是否匹配 for(int i=0;i<n;i++){ if(index1[i]==x1&&index2[i]==y1){ return 1==mapp2[x2][y2]; }//如果(x1,y1)在index数组中则值为1,就看mapp2[x2][y2]是否为1 } return 0==mapp2[x2][y2];//同理 } int main(){ cin>>n>>L>>S; for(int i=0;i<n;i++){ cin>>index1[i]>>index2[i]; } for(int i=S;i>=0;i--){ for(int j=0;j<=S;j++){ cin>>mapp2[i][j]; } } for(int i=0;i<n;i++){//枚举左下角的点 //题目说了 藏宝图左下角位置一定是一棵树 int len1=index1[i]+S,len2=index2[i]+S; if(len1>L||len2>L){//如果以当前点作为左下角的点越界了 continue; }else{ int sign=0; for(int p=0;p<=S;p++){ for(int q=0;q<=S;q++){ if(!check(index1[i]+p,index2[i]+q,p,q)){ sign=1; break; } } if(sign){ break; } } if(!sign){ ans++; } } } cout<<ans<<endl; return 0; }