解题思路:
一道区间dp的问题,一开始以为要构建树,但其实不用那么复杂。所有的数据都是有序的,可以考虑区间dp。L[i][j]代表[i,j-1]是否可作为j的左子树。R[i][j]表示[i+1,j]是否可以作为i的右子树。转移条件为:if (f[l-1][root])R[l-1][r]=1; if (f[r+1][root])L[l][r+1]=1;
当[l,r]为[1,n]时说明可以构建符合题意的树,如果枚举结束都到不了[1,n]说明不可以构建符合题意的树。f数组记录两点是否可以相连,即gcd是否大于1.初始化时注意将 L[i][i]和R[i][i]都赋值为1,因为当点i的左子树或者右子树为空时一定是符合题意的,
参考代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <algorithm>
#include <queue>
#include <vector>
#include <utility>
using namespace std;
typedef long long ll;
int t,n;
int gcd(int a,int b){
return b==0? a:gcd(b, a%b);
}
int a[705];
bool f[705][705];
bool L[705][705];
bool R[705][705];
int main(){
cin>>t;
while (t--) {
cin>>n;
bool flag=false;
for (int i=1; i<=n; i++) {
cin>>a[i];
}
memset(f, 0, sizeof(f));
memset(L, 0, sizeof(L));
memset(R, 0, sizeof(R));
for (int i=1; i<=n; i++)
for(int j=i;j<=n;j++)
{
if(gcd(a[i], a[j])>1)
f[i][j]=f[j][i]=1;
}
for (int i=1; i<=n; i++) {
L[i][i]=R[i][i]=1;
}
for(int l=n;l>=1;l--){
for(int r=l;r<=n;r++){
for(int root=l;root<=r;root++){
if(L[l][root]&&R[root][r]){
if(l==1&&r==n)
{flag=true;break;}
if (f[l-1][root])R[l-1][r]=1;
if (f[r+1][root])L[l][r+1]=1;
}
}
if(flag)break;
}
if(flag)break;
}
if(flag)cout<<"Yes\n";
else cout<<"No\n";
}
return 0;
}