[树形dp]Orgrimmar 2022杭电多校第8场 1008

Problem Description

\space \space  "In my memory, the last time such a tragic farewell to a respected Horde leader was at the top of Thunder Bluff. That day, Mother Earth was crying for him too. "

\space \space  "This time, it is the Shadow of the Horde who has left us. At this moment, the entire Horde is whispering affectionately for him. "

\space \space  "Son of Sen'jin, leader of the Darkspear tribe, Warchief of the Horde - Vol'jin."

\space \space  Born in the cunning and vicious troll race, he spent his life explaining to the world what loyalty and faith are.

A dissociation set of an undirected graph is a set of vertices such that if we keep only the edges between these vertices, each vertex in the set is connected to at most one edge.

The size of a dissociation set is defined by the size of the set of vertices.

The maximal dissociation set of the graph is defined by the dissociation set of the graph with the maximum size.

Sylvanas has a connected undirected graph that has nn vertex and n - 1n−1 edges, and she wants to find the size of the maximal dissociation set of the graph.

But since she just became the warchief of the Horde, she is too busy to solve the problem.

Please help her to do so.

Input

The input consists of multiple test cases.

The first line contains one integer T\ (1\leq T\leq 10)T (1≤T≤10) denoting the number of test cases.

The following are TT test cases.

For each test case, the first line contains one integer n\ (n\leq 500000)n (n≤500000), which is the number of vertices.

The following n - 1n−1 lines each contains two integers xx and yy denoting an edge between x and y.

It is guaranteed that the graph is connected.

Output

For each test case, output one line containing one integer indicating the answer.

Notes: In this problem, you may need more stack space to pass this problem. We suggest you to add the following code into your main function if you use C++.

int main() {
    int size(512<<20);  // 512M
    __asm__ ( "movq %0, %%rsp\n"::"r"((char*)malloc(size)+size));
    // YOUR CODE
   ...
    exit(0);
}
And if you use the code above please DON'T forget to add exit(0);exit(0); in the end of your main function, otherwise your code may get RE.

Sample Input

2

5

1 2

2 3

3 4

4 5

10

1 2

2 4

3 2

5 3

6 4

7 5

8 3

9 8

10 7

Sample Output

4

7

题意: 给出一棵树,从树中选出一个点集,要求该点集生成的子图各连通块大小最大为2,问这样的点集最大的size大小。

分析: 设状态为dp[i][1/0][1/0]表示在以i为根的子树中,选/不选i号点,选/不选i号点的子结点能得到的最大点集size,设子结点为to,那么状态转移的时候dp[i][0][1]和dp[i][0][0]都+=max(dp[to][0][0], dp[to][0][1]),而dp[i][1][1]和dp[i][0][1]表示的是选子结点,也就是至少选一个子结点,所以可以先+=子结点所有情况下的最大值,然后求出子结点中min(所有情况下的最大值-选一个子结点),最后让dp[i][1][1]和dp[i][0][1]分别加上各自的该min值。最终答案就是dp[1][1][1],dp[1][1][0],dp[1][0][1]和dp[1][0][0]中的最大值,各点初始化是dp[i][1][0] = dp[i][1][1] = 1,dp[i][0][0] = dp[i][0][1] = 0。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
using namespace std;

int dp[500005][2][2];
vector<int> tr[500005];

void dfs(int now, int fa){
	dp[now][0][0] = dp[now][0][1] = 0;
	dp[now][1][1] = dp[now][1][0] = 1;
	int t1 = inf, t2 = inf;	
	for(int i = 0; i < tr[now].size(); i++){
		int to = tr[now][i];
		if(to == fa) continue;
		dfs(to, now);
		dp[now][1][0] += max(dp[to][0][1], dp[to][0][0]);
		dp[now][0][0] += max(dp[to][0][1], dp[to][0][0]);
		dp[now][1][1] += max(dp[to][0][1], dp[to][0][0]);
		dp[now][0][1] += max(max(dp[to][0][0], dp[to][1][0]), max(dp[to][0][1], dp[to][1][1]));
		t1 = min(t1, max(dp[to][0][1], dp[to][0][0])-dp[to][1][0]);
		t2 = min(t2, max(max(dp[to][0][0], dp[to][1][0]), max(dp[to][0][1], dp[to][1][1]))-max(dp[to][1][0], dp[to][1][1]));
	}
	dp[now][1][1] -= t1;
	dp[now][0][1] -= t2;
}

signed main()
{
	int size(512<<20);  // 512M
    __asm__ ( "movq %0, %%rsp\n"::"r"((char*)malloc(size)+size));
	int T;
	cin >> T;
	while(T--){
		int n;
		scanf("%lld", &n);
		for(int i = 1; i <= n; i++) tr[i].clear();
		for(int i = 1; i < n; i++){
			int u, v;
			scanf("%lld%lld", &u, &v);
			tr[u].push_back(v);
			tr[v].push_back(u);
		}
		dfs(1, 0);
		printf("%lld\n", max(max(dp[1][0][0], dp[1][1][1]), max(dp[1][0][1], dp[1][1][0])));
	}
    exit(0);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值