hdu 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])) (当选不选,子节点可选可不选,找大的那个状态)
struct Edge{ int v,next; }edge[MAX*2]; int dp[MAX][2]; int vis[MAX]; int head[MAX]; int n; int tot; void add_edge(int a,int b){ edge[tot]=(Edge){b,head[a]}; head[a]=tot++; } void tree_dp(int u){ vis[u]=1; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(!vis[v]){ tree_dp(v); dp[u][1]+=dp[v][0]; dp[u][0]+=max(dp[v][1],dp[v][0]); } } } int main(){ while(~scanf("%d",&n)){ mem0(dp); mem0(vis); mem1(head); tot=0; for(int i=1;i<=n;i++) scanf("%d",&dp[i][1]); int a,b; while(scanf("%d%d",&a,&b)&&a&&b){ add_edge(a,b); add_edge(b,a); } tree_dp(1);//把1当作根 printf("%d\n",max(dp[1][1],dp[1][0])); } return 0; }hdu 2196
题意:给你n-1条边,每条边有权值,然后求从任意一个点开始到底的最长路径
题解:这题和树的直径挺像的,求从i点开始的最长路径,这个路径要么经过i的父节点,要么经过i的子节点,所以可以用两次dfs来维护从i开始的最长路径和次长路径(为什么要记录次长路,看代码理解比较快,因为在考虑从它父节点过来的距离的时候,如果它就是它父节点上的最长路径上的一点,那么必须考虑父节点的次长路径)
struct Edge{ int v,cost,next; }edge[MAX*2]; int maxn[MAX]; int maxid[MAX]; int smaxn[MAX]; int smaxid[MAX]; int head[MAX]; int n; int tot; void add_edge(int a,int b,int c){ edge[tot]=(Edge){b,c,head[a]}; head[a]=tot++; } void dfs1(int u,int fa){ for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; int c=edge[i].cost; if(v==fa) continue; dfs1(v,u); if(smaxn[u]<maxn[v]+c){ smaxn[u]=maxn[v]+c; smaxid[u]=v; if(smaxn[u]>maxn[u]){ swap(smaxn[u],maxn[u]); swap(maxid[u],smaxid[u]); } } } } void dfs2(int u,int fa){ for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; int c=edge[i].cost; if(v==fa) continue; if(v==maxid[u]){ if(smaxn[v]<c+smaxn[u]){ smaxn[v]=c+smaxn[u]; smaxid[v]=u; if(smaxn[v]>maxn[v]){ swap(smaxn[v],maxn[v]); swap(maxid[v],smaxid[v]); } } } else{ if(smaxn[v]<c+maxn[u]){ smaxn[v]=c+maxn[u]; smaxid[v]=u; if(smaxn[v]>maxn[v]){ swap(smaxn[v],maxn[v]); swap(maxid[v],smaxid[v]); } } } dfs2(v,u); } } int main(){ while(~scanf("%d",&n)){ mem1(head); mem0(smaxn); mem0(maxn); mem0(maxid); mem0(smaxid); tot=0; for(int i=2;i<=n;i++){ int a,b; scanf("%d%d",&a,&b); add_edge(i,a,b); add_edge(a,i,b); } dfs1(1,-1); dfs2(1,-1); for(int i=1;i<=n;i++) printf("%d\n",maxn[i]); } return 0; }