UVA - 1220 Party at Hali-Bula(树形dp)

本文介绍了一种使用树形动态规划(DP)的方法来解决一个关于团队建设的问题。通过构建一棵树来表示团队成员之间的关系,并使用一个二维DP数组来记录选择或不选择某个节点作为团队成员时的最大价值,最终找到团队的最大价值及判断方案是否唯一。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目地址点击打开链接

开始以为是各种dfs爆搜yy中。。。;

不想完全看题解,搞了很久,看了一眼后缀,据说是树形dp;

然后顿悟开始修改;随他去吧;


用一个二维dp【a】【b】 来更新最大值,a表示这个节点的编号,b有两个值,0,1表示这个点取与不取;

用一个vector来建树;从根节点开始,也就是big boss,向他的员工出发dfs,每个点可以取,也可以不取,

取:该点的所有子结点都不可取;

不取:该点的所有子节点中寻找取与不取的最大值来更新;

当到达叶子时,叶子一定是取的(max)并且dp【a】【1】值为1,因为只有这一个人;

然后就得到最大值了;


差一点gg的是,他要求你判断max的方案是否唯一,我傻,没办法,于是再来一个dfs来开始判断

取:从子节点不取中判断;

不取: 如果子节点的取和不取的值相同的话,那说明一点方案不唯一,(因为当初取的时候就是存的取和不取中的最大值,如果两者相等,则说明重复)


#include <iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<map>
#include<vector>

using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=200+5;
map<string,int>mp;
int n;
int vis[maxn];
vector<int> eg[maxn];
int flag;
int nn;
int ans;
int dp[maxn][3];
void dfs(int a,int ok)
{
     if(eg[a].size()==0&&ok)
    {
        dp[a][1]=1;
        dp[a][0]=0;
    }
    if(vis[a])
        return;
    if(ok)
     {
         dp[a][1]=1;
          for(int i=0;i<eg[a].size();i++)
        {   vis[a]=1;
            dfs(eg[a][i],0);
            dp[a][1]+=dp[eg[a][i]][0];
        }
     }
      dp[a][0]=0;
     for(int i=0;i<eg[a].size();i++)
    {

        dfs(eg[a][i],1);
         dp[a][0]+=max(dp[eg[a][i]][1],dp[eg[a][i]][0]);
    }
    if(dp[a][0]==dp[a][1])
        flag=1;
}
int oj(int a,int ok)
{
    if(ok)
    {
        for(int i=0;i<eg[a].size();i++)
          if(oj(eg[a][i],0))
            return 1;
    }
    else
    {
        for(int i=0;i<eg[a].size();i++)
        {
            if(dp[eg[a][i]][0]==dp[eg[a][i]][1])
                return 1;
        }
    }
        return 0;
}
int main()
{
   string a,b;
   while(cin>>n&&n)
   {
      cin>>a;
      int num=1;
      mp.clear();
      for(int i=0;i<=n;i++)
        eg[i].clear();
      mp[a]=num;
      for(int i=0;i<n-1;i++)
     {
        cin>>a>>b;
        if(!mp[a])
        {
          num++;
          mp[a]=num;
         }
         if(!mp[b])
         {
             num++;
             mp[b]=num;
         }
         eg[mp[b]].push_back(mp[a]);
      }
      nn=0;
      ans=0;
      flag=0;
      memset(vis,0,sizeof(vis));
      memset(dp,0,sizeof(dp));
      dfs(1,1);
      ans=max(dp[1][0],dp[1][1]);
      if(dp[1][0]==dp[1][1])
        flag=1;
      else
      {
          if(dp[1][0]>dp[1][1])
           flag=oj(1,0);
          else
           flag=oj(1,1);
      }
      cout<<ans<<" ";
      if(flag)
        cout<<"No"<<endl;
      else
        cout<<"Yes"<<endl;
   }
    return 0;
}


唉,太菜了 了 了了了了了了了了了,继续努力啊!!!

不过还好,以后一定要坚持,觉得如果自己不看题解也可以做出来的题那么,你就不要看题解!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值