[USACO08JAN]Cell Phone Network G 树形dp

题意:
John想让他的所有牛用上手机以便相互交流,他需要建立几座信号塔在N块草地中。已知与信号塔相邻的草地能收到信号。给你N-1个草地(A,B)的相邻关系,问:最少需要建多少个信号塔能实现所有草地都有信号。

思路:
开始思考的是使用dp[x][1/0]来表示结点是否有保安来解决这个问题。
但是细想了一下,父亲结点也会影响改结点的状态转移过程,所以两个结点肯定是不可以的。

d p [ x ] [ 0 / 1 / 2 ] dp[x][0/1/2] dp[x][0/1/2]来表示x结点被自己/儿子/父亲染色的最小染色数。
很容易就可以写出 d p [ x ] [ 0 ] d p [ x ] [ 2 ] dp[x][0] dp[x][2] dp[x][0]dp[x][2]的转移方程
d p [ x ] [ 0 ] + = m i n ( d p [ i ] [ 0 ] , d p [ i ] [ 1 ] , d p [ i ] [ 2 ] ) ; dp[x][0]+=min(dp[i][0],dp[i][1],dp[i][2]); dp[x][0]+=min(dp[i][0],dp[i][1],dp[i][2]); // i i i x x x的孩子结点
d p [ x ] [ 2 ] + = m i n ( d p [ i ] [ 0 ] , d p [ i ] [ 1 ] ) dp[x][2]+=min(dp[i][0],dp[i][1]) dp[x][2]+=min(dp[i][0],dp[i][1])

但是dp[x][1]似乎不是那么好转移,因为只要他有一个孩子染了色,就可以。
所以我们想,只要在保证他最少有一个孩子被染了色的情况下进行
d p [ x ] [ 1 ] + = m i n ( d p [ i ] [ 0 ] , d p [ i ] [ 1 ] ) dp[x][1]+=min(dp[i][0],dp[i][1]) dp[x][1]+=min(dp[i][0],dp[i][1])转移不就可以了。
详情见代码注释。
代码:

//#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
#define endl '\n'

vector<int> edge[maxn];
int dp[maxn][3];

void dfs(int x,int fa){
    int tot=0;dp[x][0]=1;
    int len=edge[x].size();
    for(auto i:edge[x]){
        if(i==fa) continue;
        dfs(i,x);
        dp[x][0]+=min(dp[i][0],min(dp[i][1],dp[i][2]));
        dp[x][2]+=min(dp[i][0],dp[i][1]);
        if(dp[i][0]>dp[i][1]&&tot<len-2){  
        //至少要保证有一个孩子染色了,并且父亲也连接着这个节点,
        //所以小于len-2
            dp[x][1]+=dp[i][1];tot++;
            //tot记录当前选择了几个没有被染色的孩子结点
            //要保证数量小于len-2
        }
        else dp[x][1]+=dp[i][0];
    }
    if(edge[x].size()==1&&x!=1) dp[x][1]=1e9;
}


signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin>>n;
    for(int i=0;i<n-1;i++){
        int x,y;
        cin>>x>>y;
        edge[x].push_back(y);
        edge[y].push_back(x);
    }
    dfs(1,0);
    cout<<min(dp[1][0],dp[1][1])<<endl;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值