异或生成树(树形dp)

异或生成树(树形dp)

传送门

题意:给定 n n 个结点的权值 a i [ 1 , 127 ] a_i\in[1,127] .求最大异或和生成树。

思路:答案的范围为 [ 0 , 127 ] [0,127] .考虑树形 d p dp , 设 d p [ i ] [ j ] dp[i][j] 为以结点 i i 为根的子树答案是否为 j j

对于当前结点 u u ,遍历所有的子结点 v v ,有转移方程: d p [ u ] [ i j ]   = d p [ u ] [ i ] & d p [ v ] [ j ] dp[u][i\oplus j]\ |=dp[u][i]\&dp[v][j] .

因为是从上往下遍历,所以显然这样 d p dp 思路是正确的。一开始先初始化一波 d p [ i ] [ a [ i ] ] = 1 dp[i][a[i]]=1 然后 d f s dfs 一遍即可。

时间复杂度: O ( 12 7 2 n ) 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;
} 

猜你喜欢

转载自blog.csdn.net/weixin_45750972/article/details/106310138