树上的动态规划;树的最大独立集;刷表DP,子问题彼此独立没有交集; 无根树转化有根树;

#include <iostream> #include <vector> #include <algorithm> using namespace std; /*********************************/ * 可以动态变化的邻接矩阵 * G[i]表示顶点i的邻接点 /*********************************/ const int MAXN=100; vector<int> G[MAXN]; //无根树 int l[MAXN]; //结点层次 int p[MAXN]; //根树 int dp[MAXN]; //dp数组 int sumC[MAXN]; //孩子DP和 int sumS[MAXN]; //孙子DP和 int maxL; //最大层次 int n; /*********************************/ * 读入无根树,n顶点,n-1边 /*********************************/ void readTree() { int u,v; cin>>n; for(int i=0;i<n-1;++i) { cin>>u>>v; G[u].push_back(v); G[v].push_back(u); } } /*********************************/ * 以无根树u顶点为根,构造有根树 * 主函数调用dfs(u,-1); * 测试数据: 8 0 1 1 4 0 2 0 3 1 5 5 6 5 7 /*********************************/ void dfs(int u,int fa) { int d=G[u].size(); l[u]= (fa==-1)? 0: (l[fa]+1); if(l[u]>maxL) { maxL=l[u]; } for(int i=0;i<d;++i) { int v=G[u][i]; if(v!=fa) { dfs(v,p[v]=u); } } } int rootDp(int u) { //构造u根树 p[u]=-1; maxL=-1; dfs(u,p[u]); for(int i=maxL;i>=0;--i) { for(int j=0;j<n;++j) { if(l[j]==i) { dp[j]=max(sumS[j]+1,sumC[j]); if(i-1>=0) { sumC[p[j]]+=dp[j]; } if(i-2>=0) { sumS[p[p[j]]]+=dp[j]; } } } } return dp[u]; } int main() { readTree(); int best=-1; //分别以每个顶点为根 for(int i=0;i<n;++i) { memset(sumS,0,sizeof(sumS)); memset(sumC,0,sizeof(sumC)); int tmp; if((tmp=rootDp(i))>best) { best=tmp; } } //打印结果看看 cout<<best<<endl; return 0; }

 

 

Dp: dp[u]=max{ sum(dpS[])+1, sum(dpC[])};

 

以某一个顶点为根的树,运用此DP公式.

 

意思是,

如果选结点u,那么dp[u]=孙子结点的dp[]和加自身这个结点1.

如果不选结点u,那么dp[u]=孩子结点的dp[]和.

 

代码里注释有: 无根树转化有根树算法.

 在算法中,顺便记录了每个结点的层次.

这样,在做刷表DP的时候, 可以很方便的在根树种,按层次从底向上刷表.

你可能感兴趣的:(算法,测试,include)