異或生成樹(樹形dp)

異或生成樹(樹形dp)

傳送門

題意:給定nn個結點的權值ai[1,127]a_i\in[1,127].求最大異或和生成樹。

思路:答案的範圍爲[0,127][0,127].考慮樹形dpdp, 設dp[i][j]dp[i][j]爲以結點ii爲根的子樹答案是否爲jj

對於當前結點uu,遍歷所有的子結點vv ,有轉移方程:dp[u][ij] =dp[u][i]&dp[v][j]dp[u][i\oplus j]\ |=dp[u][i]\&dp[v][j].

因爲是從上往下遍歷,所以顯然這樣dpdp思路是正確的。一開始先初始化一波dp[i][a[i]]=1dp[i][a[i]]=1然後dfsdfs一遍即可。

時間複雜度:O(1272n)O(127^2n)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e2+10;
#define mst(a) memset(a,0,sizeof a)
int n,ans,a[N];
bool jg[N],dp[N][128];
vector<int>e[N];
void dfs(int u,int fa){
      for(auto v:e[u]){
            if(v==fa) continue;
            dfs(v,u);
            mst(jg);
            for(int i=0;i<=127;i++) jg[i]=dp[u][i];
            for(int i=0;i<=127;i++){
                if(jg[i])
                for(int j=0;j<=127;j++)
                    if(dp[v][j]) dp[u][i^j]=1,ans=max(ans,i^j);
            }
      }
}
int main(){
	scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]),dp[i][a[i]]=1,ans=max(ans,a[i]);
    }
    for(int i=1,u,v;i<n;i++){
        scanf("%d%d",&u,&v);
        e[u].push_back(v),e[v].push_back(u);
    }
    dfs(1,0);
    printf("%d\n",ans);
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章