poj2342/poj3342——基础的树形DP

来源:互联网 发布:网络优化工程师面试题 编辑:程序博客网 时间:2024/04/28 16:01

poj2342:

题目大意:

大学要开年会,请公司的人来参加聚会,但是不希望员工和其最直接的上司同时出现在聚会上,问最多能邀请到多少人参加聚会。


解题思路:

转化成树的结构就是父亲节点和孩子节点不能同时出现。

设dp[i][0] 表示不取第i个人能得到的最大人数。

    dp[i][1] 表示取第i个人能得到的最大人数。

可以得到如下的状态转移方程:

dp[i][0]+=max(dp[j][0],dp[j][1])

dp[i][1]+=dp[j][0]

其中j是i的孩子节点。

所以我们只需要对根节点进行一次dfs求出所有的dp数组所有的值。

最后结果就是 max(dp[root][1] ,dp[root][0])


poj3342是上题的升级版本,除了求出最多人数之外,还需要判断最多人数的方案是否唯一。

方案唯一性的判断方法:

第1:如果dp[root][1]==dp[root][0],则方案必不唯一。

第2:如果dp[i][1]==dp[i][0],并且dp[father][0]>=dp[father][1]。

如果存在某节点其取与不取最大值是一样的,并且其父节点在不取的时候得到最大人数。

那么,这个时候方案不唯一。


poj3342源代码:

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<math.h>#include<set>#include<map>#include<vector>#include<algorithm>#include<iostream>#define INF 0x3f3f3f3fusing namespace std;typedef long long LL;const double eps=1e-8;int n;int dp[205][2];int flag;struct node{    int father;    vector<int> child;}p[205];int vis[205];void dfs(int now){    int flag1;    int i,size,child;    vis[now]=1;    size=p[now].child.size();    flag1=0;    for(i=0;i<size;i++)    {        child=p[now].child[i];        if(!vis[child])        {            dfs(child);            dp[now][0]+=max(dp[child][0],dp[child][1]);            dp[now][1]+=dp[child][0];        }    }    return;}int main(){freopen("in.txt","r",stdin);int i,x,y,cnt,j;char ch[105];string a,b;while(scanf("%d",&n)==1 && n){        map<string,int> m;    memset(p,0,sizeof(p));    cin>>a;    m[a]=1;    cnt=1;    for(i=1;i<n;i++)    {        cin>>a>>b;        x=m[a],y=m[b];        if(m[a]==0)        {            m[a]=++cnt;            x=cnt;        }        if(m[b]==0)        {            m[b]=++cnt;            y=cnt;        }        //x和y已经是映射好的值了,x是y的下属        p[y].child.push_back(x);        p[x].father=y;    }    memset(dp,0,sizeof(dp));    for(i=1;i<=n;i++)            dp[i][1]=1;        memset(vis,0,sizeof(vis));        dfs(1);        printf("%d ",max(dp[1][1],dp[1][0]));        //唯一性的判断,当前节点取和不取结果是一样的,        //并且其父亲节点不取,这样的话必然出现多种可能的选择        flag=1;        if(dp[1][1]==dp[1][0])  flag=0;        for(i=2;i<=n;i++)        {            if(dp[i][1]==dp[i][0] && dp[p[i].father][0]>=dp[p[i].father][1])            {                flag=0;                break;            }        }        if(flag)    printf("Yes\n");    //是独一无二的        else        printf("No\n");     //不是独一无二的        m.clear();                      //用完之后将m清空}return 0;}

原创粉丝点击