1. 程式人生 > >2018GDUT第一場C 遺失的二叉樹(區間dp)

2018GDUT第一場C 遺失的二叉樹(區間dp)

問題描述:

給定一個序列,判斷其是否可能為一個二叉樹的中序遍歷序列,該二叉樹樹邊連線的兩個點的值不能互質。

輸入描述:

第一行一個數字T,表示測試組數

對於每一組測試樣例

第一行一個數字n,表示序列長度

第二行有n個數字ai,表示這個序列

T≤5,n≤500,2≤ai≤10^9

輸出格式:

輸出T行,"Yes"或"No"

輸入樣例:

2
6
5 4 7 9 5 4
4
2 6 3 4

輸出樣例:

No
Yes

題目分析:

n才500,預處理出 ok[i][j] 表示a[i]與a[j]之間可以連樹邊。接下來考慮區間 dp,L[l][r]表示區間[l,r] 是否可以作為 r 的左兒子,R[l][r]表示區間[l,r]是否可以作為 l 的右兒子。

那麼 L[l][r]=true 的前提是存在一個k(l≤k≤r-1)滿足: L[l][k]&&R[k][r-1]&&ok[k][r]

同理 R[l][r]=true 的前提是存在一個k(l+1≤k≤r)滿足:L[l+1][k]&&R[k][r]&&ok[l][k]

分析之後發現區間dp複雜度為n^3,n為500,樣例好像比較水,1s時間能過。

AC程式碼:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
#define lowbit(a) ((a)&(-(a)))
#define ll long long
using namespace std;
int n,m,a[505];
bool L[505][505],R[505][505],ok[505][505];
inline void init(){
    for(int i=1;i<=n;i++){
        L[i][i]=R[i][i]=ok[i][i]=1;
        for(int j=1;j<i;j++){
            L[i][j]=L[j][i]=R[i][j]=R[j][i]=ok[i][j]=ok[j][i]=0;
        }
    }
}
int main(){
    int t;  scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        
        for(int i=1;i<=n;i++){          //預處理
            for(int j=1;j<i;j++){
                if(__gcd(a[i],a[j])!=1)ok[i][j]=ok[j][i]=true;
                else ok[i][j]=ok[j][i]=false;
            }
        }
        
        for(int len=1;len<=n;len++){
            
            for(int i=len+1;i<=n;i++)  //L[i-len][i]
                for(int j=i-len;j<=i-1;j++)
                    if(L[i-len][j]&&R[j][i-1]&&ok[i][j]){
                        L[i-len][i]=true;
                        break;
                    }
            
            for(int i=1;i<=n-len;i++)  //R[i][i+len]
                for(int j=i+1;j<=i+len;j++)
                    if(L[i+1][j]&&R[j][i+len]&&ok[i][j]){
                        R[i][i+len]=true;
                        break;
                    }
            
        }
        
        bool flag=false;
        for(int i=1;i<=n;i++)
            if(L[1][i]&&R[i][n]){
                flag=true;
                break;
            }
        if(flag)
            puts("Yes");
        else
            puts("No");
    }
	return 0;
}