UVa Placing Lampposts 树型DP

来源:互联网 发布:bnc接口怎么转网络接口 编辑:程序博客网 时间:2024/05/14 13:37

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

        首先,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   2000using 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
原创粉丝点击