树状DP入门
来源:互联网 发布:安卓手机连接mac电脑 编辑:程序博客网 时间:2024/05/20 03:44
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520
题目大意:给定一棵关系树,每个节点有个权值,子节点和父节点不能同时选,问最后能选的最大价值是多少?
解题思路:树形DP入门题。由于子节点与父节点不能同时选,有人可能会用贪心思想,二者选其一肯定最优。其实不然,有可能父节点和子节点都不选,而要选子孙节点。不过只要再往深点想下,就可以得出动态规划的解法。每个节点要么选要么不选,和大多数选不选动归一样,来个dp[i][2],0表示不选,1表示不选,那我们只要从叶子节点往根结点不断更新dp[i][0]和dp[i][1]就可以了。
状态转移方程:dp[i[[1] = sum(dp[j][0]) (当前选了,子节点必定不能选,最优的情况是都不选,然后累加)
dp[i][0] = sum(max(dp[i][0],dp[i][1])) (当选不选,子节点可选可不选,找大的那个状态)
简单的树形DP入门题
分别用STL中的vector建了个有向图
然后又用结构体建了个无向图。
两个程序
#include<iostream>#include<vector>#include<cmath>#include<cstdio>using namespace std;#define MAXSIZE 6050vector<int> vec[MAXSIZE];int weight[MAXSIZE];int f[MAXSIZE]; //每个节点的父节点int d[MAXSIZE][2];int num;//d[a][0]表示不选择该节点,d[a][1]表示选择该节点void dfs(int a) //用来求解d[a][0]和d[a][i]{ unsigned int i; unsigned int len=vec[a].size(); d[a][1]=weight[a]; for(i=0;i<len;i++) dfs(vec[a][i]); for(i=0;i<len;i++) { d[a][1]+=d[vec[a][i]][0]; d[a][0]+=max(d[vec[a][i]][0],d[vec[a][i]][1]); }}int main(){ int i,a,b; //freopen("a.txt","r",stdin); while(scanf("%d",&num)!=EOF) { for(i=1;i<=num;i++) { scanf("%d",&weight[i]); vec[i].clear(); d[i][0]=d[i][1]=0; f[i]=-1;//初始化的时候都是没有父节点的 } while(scanf("%d%d",&a,&b),a+b) { f[a]=b; vec[b].push_back(a); } a=1; while(f[a]!=-1) a=f[a]; dfs(a); cout<<max(d[a][0],d[a][1])<<endl; } return 0;}
<pre name="code" class="cpp">//第二种方法,用结构体来构建无向图#include<cstdio>#include<algorithm>#include<cstring>using namespace std;#define MAXN 6050struct node{ int v; node* next;}*head[MAXN],tree[MAXN*2];bool vis[MAXN];int weight[MAXN];int ptr,num;int d[MAXN][2];void init(){ ptr=1; memset(vis,false,sizeof(vis)); memset(head,NULL,sizeof(head));}void addEdge(int a,int b) //该段是模块化编程{ //所有的关于树形DP问题采用无向图方式表示地 tree[ptr].v=b; //都是这样构造无向图的 tree[ptr].next=head[a]; //采用2个一维的数组表示的 head[a]=&tree[ptr++]; tree[ptr].v=a; tree[ptr].next=head[b]; head[b]=&tree[ptr++];}void bfs(int root){ if(vis[root]) //记忆化搜索,vis[root]为true表示已经求过d[root] return ; vis[root]=true; d[root][1]=weight[root]; node* p=head[root]; while(p) { if(!vis[p->v]) //只有没访问过才求其值 { bfs(p->v); d[root][1]+=d[p->v][0]; d[root][0]+=max(d[p->v][0],d[p->v][1]); } p=p->next; }}int main(){ int i,a,b; freopen("a.txt","r",stdin); while(scanf("%d",&num)!=EOF) { init(); for(i=1;i<=num;i++) scanf("%d",&weight[i]); while(scanf("%d%d",&a,&b),a+b) addEdge(a,b); bfs(1); printf("%d\n",max(d[1][0],d[1][1])); }}
0 0
- 树状DP入门
- hdu1011 树状dp入门
- ZOJ3201 Tree of Tree 树状dp入门
- POJ 2342 (树状DP)入门
- hdu_2196 computer 树状dp经典入门题
- HDU 1520-Anniversary party(树状DP入门)
- 树状DP
- 树状DP
- 树状DP
- 选课 树状DP
- HDU1054 树状DP
- HDU2412 树状DP
- 【树状DP】ural 1018
- hdu 3586 树状dp
- hdu 1520 树状 dp
- poj1848 树状DP
- HDU 2412 树状DP
- HDU 2196 树状DP
- 深入Android开发之--理解View#onTouchEvent
- Js获取当前日期时间及其它操作
- 步进电机驱动微型输注仪器的一种新方式
- Java 常量池
- 小波变换 wavelet
- 树状DP入门
- 学习读懂时序图
- 信号量集
- 利用高性能模拟器件简化便携式医疗设备设计
- 从技术岗位走向管理岗位:机会是留给有准备的人
- Hibernate中配置C3P0连接池
- printf()格式化输出特殊用法
- 常用PHP语句
- Android代码工具集——判断网络是否可用