AOJ 911 组队分配 【树形DP】

---恢复内容开始---

题面:

有一个n个节点n-1条边组成的树。
每个点看成一个人,连接u和v的边看成是“中意关系”,即u和v两个人都想和对方组队。每个人希望组队的对象有可能有多个。
一支队伍由且仅由两个人组成,并且如果u和v组队了,那么u、v将不能和其他人再组成一支队。
现在问你,这n个人最多能组成多少支队伍。(允许某些人组不了队)

Input

第一行输入一个整数n,m(1<=n<=200000)
接下来n-1行,每行两个整数u,v,表示u和v两个人都想和对方组队。
数据保证是一个合法的树。

Output

输出一个整数,表示最多能组成多少支队伍。

Input

5

1 2

1 3

2 4

4 5

Output

2

大致思路:

首先看到题面,其实很容易想到是一道树形DP。但树上的关系在比赛时间里没有想明白,导致没有做出来。

对于每一个节点,都有取或者不取两个可能。分别用dp[k][1]和dp[k][0]来表示

然后就是节点之间的关系了,对于每一个节点来说,若不取这个点,则肯定是对于每一个子节点的取或者不取求一个max

也就是 dp[k][0]+=max(dp[ v ] [ 1 ] , dp [ v ] [ 0 ] )  v是k的子节点

但对于dp[k][1]就有点麻烦了,因为如果要让dp[k][1]成立,则必然有至少加上一个子节点不取的情况。

 1 void tree_dp(int k,int last)
 2 {
 3     int v;
 4     bool flag=false;
 5     for(int i=0;i<g[k].size();++i){
 6         v=g[k][i];
 7         if(v==last)
 8             continue;
 9         tree_dp(v,k);
10         if(dp[v][1]>dp[v][0])//对每一个dp[v]进行选择,如果取的情况值较大,就直接加到dp[v][0]上
11 dp[k][0]+=dp[v][1]; 12 else{//否则就表示第k个节点是可以取到的,同时标记flag。 13 flag=true; 14 dp[k][0]+=dp[v][0];//这里依然加给dp[v][0]是因为在最后会加给dp[k][1],而且第k个点最多只能取一次
15 } 16 } 17 dp[k][1]=dp[k][0];//如果第k个取不到,直接赋值给dp[k][1],对下一层决策无影响 18 if(flag) 19 dp[k][1]++; 20 }

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=2e5+7;
 4 int dp[maxn][2],ans=0;
 5 vector<int> g[maxn];
 6 void tree_dp(int k,int last)
 7 {
 8     int v;
 9     bool flag=false;
10     for(int i=0;i<g[k].size();++i){
11         v=g[k][i];
12         if(v==last)
13             continue;
14         tree_dp(v,k);
15         if(dp[v][1]>dp[v][0])
16             dp[k][0]+=dp[v][1];
17         else{
18             flag=true;
19             dp[k][0]+=dp[v][0];
20         }
21     }
22     dp[k][1]=dp[k][0];
23     if(flag)
24         dp[k][1]++;
25 }
26 int main()
27 {
28     ios::sync_with_stdio(false);
29     //freopen("in.txt","r",stdin);
30     //freopen("ou1.txt","w",stdout);
31     memset(dp,0,sizeof(dp));
32     int n,u,v;
33     cin>>n;
34     for(int i=0;i<n-1;++i){
35         cin>>u>>v;
36         g[u].push_back(v);
37         g[v].push_back(u);
38     }
39     tree_dp(1,1);
40     //for(int i=1;i<=n;++i)
41      //   cout<<i<<" "<<dp[i][1]<<" "<<dp[i][0]<<endl;
42     ans=max(dp[1][0],dp[1][1]);
43     cout<<ans<<endl;
44     return 0;
45 }

---恢复内容结束---

原文地址:https://www.cnblogs.com/SCaryon/p/7482214.html