ZOJ_2834 树形DP
来源:互联网 发布:网络写作集剧本编写 编辑:程序博客网 时间:2024/05/29 14:34
题目意思太罗嗦,不解释了。这道题一开始一直Segmentation Fault,问了秦总才发现可能是数组放在dfs里面的关心后来又wa了无数次,结果是因为它居然可以是个森林!!!简直报警了,题目中明明说的是Koopa的所有儿子,居然还可以存在森林。唉。。。
这道题好事蛮不错的一道题,每一个点有三种状态:dp[i][0],dp[i][1],dp[i][2]。dp[i][1]代表第i个人刚刚被干掉,第i个节点及其子树的最大值。dp[i][0]代表第i个节点即所有节点的t[i]值之和。dp[i][2]代表的是第i个节点没有被干掉所能干掉其子树的最大值和。
下面来写转移方程:
dp[u][0] = t[u] + sum{dp[v][0]};
dp[u][2] = max{dp[v][0] + sum{dp[w][2] | w != v} = max{dp[v][0]-dp[v][2])}+ sum{dp[v][2]}; 这两个v相互独立
dp[u][1] = max{dp[v][0]-dp[v][2] + dp[w][1] - dp[w][2] | w != v} + sum{dp[v][2]};
注意下一边界条件就可以开始写了。。。算 dp[v][0]-dp[v][2]+dp[w][1]-dp[w][2]的最大值的时候有一个小技巧,直接看我的代码:
#include <iostream>#include <cstdio>#include <cstring>#include <vector>#include <algorithm>#define FOR(i,x,y) for(int i = x;i < y;i ++)using namespace std;const int MAXN = 2222;int n,dp[MAXN][3],t[MAXN],head[MAXN],edge_cnt; //dp[i][0]表示i个节点和他的所有子树都被杀了,dp[i][1]表示第一次i个节点被杀了,dp[i][2]表示i个节点没被杀int st[MAXN];struct Edge{ int to,next;}edge[MAXN<<1];bool cmp(int x,int y) {return x>y;}void add_edge(int u,int v){ edge[edge_cnt].to = v; edge[edge_cnt].next = head[u]; head[u] = edge_cnt++;}void dfs(int u,int fa){ dp[u][0] = dp[u][1] = t[u]; dp[u][2] = 0; int cnt = 0; int dp2 = -1; int sum = 0; int dp00 = -1,dp01 = -1,dp10 = -1,dp11 = -1; ///dp00 代表dp[v][0]-dp[v][2]的最大值,dp01代表第二大值,dp10同理 for(int i = head[u];i != -1;i = edge[i].next){ int v = edge[i].to; if(v == fa) continue; dfs(v,u); dp[u][0] += dp[v][0]; sum += dp[v][2]; if((dp[v][0]-dp[v][2]) >= dp00){ dp01 = dp00; dp00 = dp[v][0]-dp[v][2]; } else dp01 = max(dp01,t[v]); if(dp[v][1]-dp[v][2] >= dp10){ dp11 = dp10; dp10 = dp[v][1]-dp[v][2]; } else dp11 = max(dp11,dp[v][1]-dp[v][2]); dp2 = max(dp2,dp[v][0]-dp[v][2]+dp[v][1]-dp[v][2]); cnt++; } if(!cnt) return; if(cnt == 1){ dp[u][1] += sum+dp00; dp[u][2] += sum+dp00; } else{ if(dp00 + dp10 == dp2) { if(dp01 == dp00 || dp11 == dp10) dp[u][1] += sum+dp2; else dp[u][1] += sum+max(dp00+dp11,dp01+dp10); } else dp[u][1] += sum + dp00 + dp10; dp[u][2] += sum+dp00; } return;}int dfs2(int u,int fa){ int ans = t[u]; for(int i = head[u];i != -1;i = edge[i].next){ int v = edge[i].to; if(v == fa) continue; ans += dfs2(v,u); } return ans;}int main(){ freopen("test.in","r",stdin); while(~scanf("%d",&n) && n){ memset(head,-1,sizeof(head)); edge_cnt =0; FOR(i,0,n) scanf("%d",&t[i]); int to; int st_cnt = 0; FOR(i,0,n){ scanf("%d",&to); if(to == -1){ st[st_cnt++] = i; continue; } add_edge(i,to); add_edge(to,i); } int ans = 0; FOR(i,0,st_cnt-1) ans += dfs2(st[i],-1); dfs(n-1,-1); printf("%d\n",ans+dp[n-1][1]); } return 0;}
0 0
- ZOJ_2834 树形DP
- 树形dp
- 树形DP
- 树形dp
- 树形DP
- 树形dp
- 树形DP
- 树形DP
- 树形DP
- 树形DP
- 树形dp
- 树形dp
- 树形dp
- 树形dp
- 树形DP
- 树形DP
- 树形DP
- 树形DP
- 第三章 第十五题
- http与https的区别
- WCF实现双工通信
- 论搜索引擎solr与MongoDB的整合
- 第三章第29题种子产生随机数数组
- ZOJ_2834 树形DP
- 玩命牛的成长记录(十五)——需求
- Android之ksoap2-android详解与调用天气预报Webservice完整实例
- 项目期---项目的搭建的准备工作
- PX4飞控中利用EKF估计姿态角代码详解
- Liunx编程之信号signal
- 用数组作为函数返回值
- Android系统截屏功能提取
- Windows 7系统64位下vpn连接789错误解决方法