Step1 Problem:
给你 n 个点,升序给出 n 个点的权值,让你判断是否能构成一棵排序树:两个节点权值的 gcd 不等于 1 才能够连边。
数据范围:
2 <= n <= 700, 2 <= a[i] <= 1e9.
Step2 Ideas:
扩充知识:通常情况下,1字节 = 8位. C++ 里面 int 占 4字节,char 占 1字节,bool 占 1字节,bitset 占 1位。
dp[L][R][fa]:子树 L 到 R, 父亲是 fa 是否能构成满足条件的排序树。
int:700*700*700 = 343000000
bool:700*700*700/4 = 85750000 (相当于 int 数组大小)
bitset:700*700*700 / 32 = 10718750(相当于 int 数组大小)
用 bitset,就不会被卡内存了
另外一种思路可以把内存降下来:
dp[L][R][2]:dp[L][R][0], 代表子树 L 到 R, L 为父亲;dp[L][R][1], 代表子树 L 到 R, R 为父亲。
Step3 Code:
#include<bits/stdc++.h>
using namespace std;
const int N = 705;
bitset<710> vis[N][N], dp[N][N];
int a[N], g[N][N];
int dfs(int l, int r, int fa)
{
if(l > r) return 1;//空树返回 1
if(vis[l][r][fa]) return dp[l][r][fa];// 记忆化
vis[l][r][fa] = 1;// 标记这个状态已经走过
if(l == r) {//根节点 直接判断
if(g[l][fa] != 1) return 1;
else return 0;
}
for(int root = l; root <= r; root++)// 枚举区间 l, r 的根
{
if(g[root][fa] != 1) {
if(dfs(l, root-1, root) && dfs(root+1, r, root)) return dp[l][r][fa] = 1;
}
}
return dp[l][r][fa] = 0;
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", a+i);
for(int i = 1; i <= n; i++)//预处理出两个点的 gcd
{
for(int j = 1; j <= n; j++)
g[i][j] = __gcd(a[i], a[j]);
}
memset(vis, 0, sizeof(vis));
memset(dp, 0, sizeof(dp));
if(dfs(1, n, 0)) printf("Yes\n");
else printf("No\n");
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N = 705;
int dp[N][N][2];// 0 代表 L 为父亲,1 代表 R 为父亲
int a[N], g[N][N];
int dfs(int l, int r, int fa)
{
if(l == r) return 1;
// printf("%d %d %d\n", l, r, fa);
if(dp[l][r][fa] != -1) return dp[l][r][fa];
if(r-l == 1) {
if(g[l][r] != 1) return 1;
else return 0;
}
for(int root = l; root <= r; root++)
{
if(!fa && root != l) {
if(g[root][l] != 1) {
if(dfs(l+1, root, 1) && dfs(root, r, 0)) return dp[l][r][fa] = 1;
}
}
if(fa && root != r) {
if(g[root][r] != 1) {
if(dfs(l, root, 1) && dfs(root, r-1, 0)) return dp[l][r][fa] = 1;
}
}
}
return dp[l][r][fa] = 0;
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", a+i);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
g[i][j] = __gcd(a[i], a[j]);
}
memset(dp, -1, sizeof(dp));
for(int root = 1; root <= n; root++)
{
if(root == 1) {
if(dfs(root, n, 0)) {
printf("Yes\n");
return 0;
}
}
else if(root == n) {
if(dfs(1, root, 1)) {
printf("Yes\n");
return 0;
}
}
else if(dfs(1, root, 1) && dfs(root, n, 0)) {
printf("Yes\n");
return 0;
}
}
printf("No\n");
return 0;
}