树形dp compare E - Cell Phone Network POJ - 3659 B - Strategic game POJ - 1463

B - Strategic game

POJ - 1463

题目大意:给你一棵树,让你放最少的东西来覆盖所有的边

这个题目之前写过,就是一个简单的树形dp的板题,因为这个每一个节点都需要挺好处理的。

这个树形dp是从底往根部来递推,所以每一个点,都是由它的根节点来递推的。

如果一个根节点的子节点放了东西,那么这个根节点就可以有选择,但是如果没有放东西,那么这个根节点就必须放东西。

E - Cell Phone Network

POJ - 3659

题目大意:给你一棵树,让你用最小的东西来覆盖所有的点。

这个题目和上面那个很像,但是有点不太一样,如果是覆盖所有的点,就不一点要覆盖所有的边,但是如果覆盖了所有的边就肯定会覆盖所有的点。

那么这个题目应该怎么考虑呢,这个同样是一个树形dp,每一个点都是由它的子节点推过来的。

这个就和上面那个有一点不太一样,但是很像。

上面那个对于每一个根节点,只要有一个子节点没有放东西,那么这个根节点肯定要放东西。

而这个题目就不太一样,对于每一个节点,如果想要被覆盖,那么有三种可能,一个是它本身放了东西,一个是它的父节点放了东西,一个是它的子节点放了东西。

所以这个dp对于每一个节点就可以有三种状态。

dp[cur][0]表示这个点被放了东西

dp[cur][1]表示这个点的子节点被放了东西。

dp[cur][2]表示这个点的父节点被放了东西

状态定义好了,这个转移方程就比较好写了。

dp[cur][0]=min(dp[x][0],dp[x][1],dp[x][2])     如果它被放了东西,那么它的子节点就肯定已经被覆盖了

dp[cur][1]=min(dp[x][0],dp[x][1])    这个为什么没有dp[x][2]因为我们已经确定cur这个节点不会放东西。

dp[cur][2]=min(dp[x][0],dp[x][1])    为什么这个dp[x][2]没有呢,理由同上。

但是这个还有一点点小问题要注意

第一个就是dp[cur][0]=1 因为这个点被放了东西,所以要+1

但是dp[cur][1]不需要给她初值1 因为它是由它的子节点推过来 而子节点已经被赋值过了。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <iostream>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 100;
int dp[maxn][4];
vector<int>G[maxn];

void dfs(int u,int pre)
{
//    printf("www dp[%d][0]=%d dp[%d][1]=%d dp[%d][2]=%d\n", u, dp[u][0], u, dp[u][1], u, dp[u][2]);
    bool ok = false;
    int dif = inf;
    for(int i=0;i<G[u].size();i++)
    {
        int v = G[u][i];
        if (v == pre) continue;
        dfs(v, u);
    }
    for(int i=0;i<G[u].size();i++)
    {
        int v = G[u][i];
        if (v == pre) continue;
        dp[u][0] += min(min(dp[v][1], dp[v][0]), dp[v][2]);
        dp[u][2] += min(dp[v][1], dp[v][0]);
        dif = min(dif, abs(dp[v][1] - dp[v][0]));
        if(dp[v][0]<dp[v][1])
        {
            ok = true;
            dp[u][1] += dp[v][0];
        }
        else dp[u][1] += dp[v][1];
    }
    if (!ok) dp[u][1] += dif;
    //printf("dp[%d][0]=%d dp[%d][1]=%d dp[%d][2]=%d\n", u, dp[u][0], u, dp[u][1], u, dp[u][2]);
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i=1;i<n;i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    for (int i = 1; i <= n; i++) dp[i][0] = 1;
    dfs(1, -1);
    printf("%d\n", min(dp[1][0], dp[1][1]));
    return 0;
}

树形dp

原文地址:https://www.cnblogs.com/EchoZQN/p/11009125.html

时间: 2024-08-29 10:48:02

树形dp compare E - Cell Phone Network POJ - 3659 B - Strategic game POJ - 1463的相关文章

poj3659 Cell Phone Network(最小支配集-树形dp)

题目链接:点击打开链接 题目描述:给定一棵树,从中选取尽量少的点使每个点要么被选中,要么和被选中的点直接相连? 解题思路:树上的最小支配集,树形dp dp[i][0]:选中i作为支配集 dp[i][1]:不选i作为支配集,但其子节点覆盖了i dp[i][2]:不选i作为支配集,而且其子节点没有覆盖i 代码: #pragma comment(linker,"/STACK:1024000000,1024000000") #include <cstdio> #include &l

【POJ 3659】Cell Phone Network

Cell Phone Network Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6012   Accepted: 2163 Description Farmer John has decided to give each of his cows a cell phone in hopes to encourage their social interaction. This, however, requires hi

poj 3342(树形dp)

题意:在一个公司中要举办一个聚会,每一个员工有一个奉献值.为了和谐规定直接上下级不能一起出席.让你找出奉献值之和最大为多少. 思路:dp[v][1]表示当前结点选,能获得的最大奉献值,dp[v][0]表示当前节点不选能获得的最大奉献值.状态转移: dp[v][0] = max(dp[v][0], ∑max(dp[x][1], dp[x][0]))x为直接儿子 dp[v][1] = max(dp[v][1], ∑dp[x][0] + vex[v]) 最后答案是max(dp[root][0], dp

poj 4045 Power Station(初涉树形dp)

http://poj.org/problem?id=4045 大致题意:有n个村庄,求将发电站建在哪一个村庄使得花费最少.这是一个无向无环图.简化一下就是求一个节点使它到其他所有节点的距离和最小. 起初一直在向最短路上靠,但因为节点和边数太大,必定TLE.然后无比强大的啸神随便写了两个dfs就过掉了,简直膜拜.赛后搜了搜题解,发现这是道树形dp.sad,真的要好好刷dp了. 大体思路是将这个无向无环图看做一个树,我们就在这个树上进行动态规划.首先先随便拿一个节点看做根节点(假设节点1),计算出它

poj 1655 and 3107 and 2378 树形dp(树的重心问题)

简单的树形dp,顺便学习了树的重心的概念,即以该点为根的树的最大子树的结点数最少. poj 1655: 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 20001; 7 int head[N]; 8 int balance[N]; 9 int child[N]; 10 int n, e; 11 12 struct

[POJ 1947]Rebuilding Roads (树形dp)

题目链接:http://poj.org/problem?id=1947 题目大意:给你一棵树,树上N个节点.问最少拆掉多少条边使得存在一个联通块,有P个节点. 树形dp,设计状态:dp[u][i]代表以u为根节点的剩下i个节点最少需要拆掉多少条边. 状态转移:dp[u][i+j] = min(dp[u][i+j],dp[u][i]+dp[v][j]-1); 其中v是u的儿子节点. 相当于在树上跑01背包,即每个儿子节点去掉剩下j个的但是要连上u-v边,或者不去掉剩下j个的. 代码: 1 impo

poj 1947(树形dp)

题意:一棵树上问你最少切掉几条边使得能分割出一个结点数正好为k的子树. 思路:dp[i][j]表示以i为根切掉j个结点最少要几条边. dp[v][j] = min(dp[v][j], dp[v][j-k] + dp[x][k]); 代码如下: 1 dp[v][j] = min(dp[v][j], dp[v][j-k] + dp[x][k]); 2 } 3 } 4 } 5 } 6 } 7 return vex[v]; 8 } 9 10 int main() 11 { 12 // freopen("

POJ 2342 (树形DP)

Anniversary party Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3863   Accepted: 2172 Description There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure

SGU 149. Computer Network( 树形dp )

题目大意:给N个点,求每个点的与其他点距离最大值 很经典的树形dp...很久前就想写来着...看了陈老师的code才会的...mx[x][0], mx[x][1]分别表示x点子树里最长的2个距离, dfs一遍得到. mx[x][2]表示从x的父亲到x的最长路径长度, 也是dfs一遍得到(具体看代码).最后答案就是max(mx[x][0], mx[x][2]). 时间复杂度O(N) ----------------------------------------------------------