C-宇宙狗的危机
一、题目描述
二、思路与算法
本题在代码中的注释有详细说明。
核心算法就是通过递归,判断目前这个节点是否可以作为根节点。
- 那么,如何递归确定?
答:要想让某节点可以作为二叉搜索树的根节点,那么这个节点的左子树、右子树都必须可行。那么,我们又要去分别看左、右子树。两者判断方法相似,以左子树判断为例:
if(!vis_l[l+1][now+1]){ //左侧没有计算过
bool flag=false;
if(l==now-1){flag=true;} //左子树为空 一定可行
for(int i=l+1;i<now;i++){
if(all_gcd[i][now]>1){ //gcd>1
if(jud(l,i,now)){flag=true;}
//递归判断左子树能否以当前节点为根,l~i为它的左子树,i~now是它的右子树
//以此类推直到左子树每个点的位置都确定下来
}
} //能找到一个节点,作为now的左孩子,且左子树可行
vis_l[l+1][now+1]=true;
result_l[l+1][now+1]=flag;
}
vis的两个数组用来记录是否计算过这个区间的可行性,如果没有计算过可行性,就进行上方代码。
三、代码实现
#include<iostream>
#include<math.h>
#include<algorithm>
#include<string.h>
using namespace std;
int a[710];
int all_gcd[710][710];
bool vis_l[710][710]; //是否已经计算过这部分的可行性
bool vis_r[710][710];
bool result_l[710][710]; //记录这部分的可行性
bool result_r[710][710];
int n,t;
int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } //求gcd
bool jud(int l,int now,int r){ //判断以now为根节点构造二叉搜索树是否可行
if(vis_l[l+1][now+1]&&vis_r[now+1][r+1]){ //如果左右都计算过
return (result_l[l+1][now+1]&&result_r[now+1][r+1]);
//直接返回两者可行性的与(两者都可,now才能做根)
}
if(l>=now-1&&r<=now+1){
return true;
}
if(!vis_l[l+1][now+1]){ //左侧没有计算过
bool flag=false;
if(l==now-1){flag=true;} //左子树为空 一定可行
for(int i=l+1;i<now;i++){
if(all_gcd[i][now]>1){
if(jud(l,i,now)){flag=true;}
}
} //能找到一个节点,作为now的左孩子,且左子树可行
vis_l[l+1][now+1]=true;
result_l[l+1][now+1]=flag;
}
if(!vis_r[now+1][r+1]){ //右侧没有计算过
bool flagr=false;
if(now==r-1){flagr=true;}
for(int i=now+1;i<r;i++){
if(all_gcd[now][i]>1){
if(jud(now,i,r)){flagr=true;}
}
} //能找到一个节点,作为now的右孩子,且右子树可行
vis_r[now+1][r+1]=true;
result_r[now+1][r+1]=flagr;
}
return (result_l[l+1][now+1]&&result_r[now+1][r+1]);
//如果左右子树都可行,now可做根
}
void init(){
for(int i=0;i<710;i++){
for(int j=0;j<710;j++){
vis_l[i][j]=0;
vis_r[i][j]=0;
result_l[i][j]=0;
result_r[i][j]=0;
}
}
}
int main(){
scanf("%d",&t);
for(int i=0;i<t;i++){
init();
scanf("%d",&n);
for(int j=0;j<n;j++){
scanf("%d",&a[j]);
}
for(int j=0;j<n;j++){
for(int k=j;k<n;k++){
all_gcd[j][k]=gcd(a[j],a[k]);
all_gcd[k][j]=all_gcd[j][k];
}
}
int flag=0; //标志量,确定是否是break出来的
for (int j=0;j<n;j++)
{
if(jud(-1,j,n)){
flag=1;
}
}
if (flag==1){
cout<<"Yes\n";
}
else{cout<<"No\n";}
}
}
四、经验与总结
- 注意输出!!因为题目要输出Yes/No,而我输出YES/NO,几乎WA了一上午,一定要细心!注意输入输出格式!