UVa Placing Lampposts 树型DP

        大致思路和大白书上的相同,不过感觉书上的决策部分讲解的并不是非常清楚,因此我在这里讲解一下我的决策思路。

        首先,d(i,j)表示根节点为i的子树,当它的父节点为j(j=0或1)时的x的最小值(x的含义书上有讲解),要将该子树根节点和父节点相连的边的情况计算在内。接下来遍历森林中的每一棵树,对于每一棵树的根节点进行特别的处理,然后就对该树进行深度优先搜索dfs(i)。

        对于d[i][0]的情况,因为当前子树根节点i的父节点为0,所以该子树根节点的状态必为1,则d[i][0]=sum{d[k][1]|k为i的子节点}+M+1。然而,对于d[i][1]则需要分两种情况进行讨论:当i为1时,d1=sum{d[k][1]|k为i的子节点}+M,当i为0时,d0=sum{d[k][0]|k为i的子节点}+1,则d[i][1]=min(d0,d1)。最后每棵树的根节点都按照自身为1和自身为0,分别加上对于的sum{d[k][j]|k为对应根节点的子节点}即可。详细解答见代码。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAX 1000+5
#define M   2000
using namespace std;

int T,n,m,x;
int G[MAX][MAX],vis[MAX],d[MAX][2];
void dfs(int);

int main()
{
    cin>>T;
    while(T--){
        cin>>n>>m;
        memset(G,0,sizeof(G));
        x=0;

        int a,b;
        for(int i=0;i<m;++i){
            cin>>a>>b;
            G[a][b]=G[b][a]=1;
        }

        memset(vis,0,sizeof(vis));
        memset(d,0,sizeof(d));

        for(int i=0;i<n;++i) if(!vis[i]){
            vis[i]=1;
            int d0=0,d1=0;

            for(int j=0;j<n;++j) if(G[i][j]){
                dfs(j);
                d0+=d[j][0];
                d1+=d[j][1];
            }
            d1+=M;
            x+=min(d0,d1);
           
        }
        cout<<x/M<<" "<<m-x%M<<" "<<x%M<<endl;
    }

    return 0;
}

void dfs(int root)
{
    int leaf=1,d0=0,d1=0;
    vis[root]=1;

    for(int i=0;i<n;++i) if(!vis[i]&&G[root][i]){
        leaf=0;
        dfs(i);
        d[root][0]+=d[i][1];
        d0+=d[i][0];
        d1+=d[i][1];
    }
    d[root][0]+=M+1;
    d[root][1]=min(d1+M,d0+1);

    if(leaf){//叶子节点特殊处理
        d[root][0]=M+1;
        d[root][1]=1;
    }

    return;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值