异或生成树(树形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;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章