树上的动态规划

1.树的最大独立集

对于一颗n结点的无根树,选出尽量多的结点,使得任何两个结点均不相邻,然后输入n-1条无向边,输出一个最大独立集。

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>

using namespace std;

#define maxn 100
vector<int> v[maxn];
int d[maxn], s[maxn], gs[maxn];
int dfs(int n, int fa)
{
    for(int i = 0; i < v[n].size(); i++)
    {
        int m = v[n][i];
        if(m != fa)dfs(m, n);
        s[n] += d[m];
        if(fa != -1)
            gs[fa] += d[m];
    }
    d[n] = max(s[n], gs[n] + 1);
    return d[n];
}
int main()
{
    int n;
    while(cin >> n)
    {
      for(int i = 0; i < n; i++)
          v[i].clear();
      for(int i = 0; i < n-1; i++)
      {
        int a, b;
        cin >> a >> b;;
        v[a].push_back(b);
        v[b].push_back(a);
      }
      memset(d, 0, sizeof(d));
      memset(s, 0, sizeof(s));
      memset(gs, 0, sizeof(gs));
      cout << dfs(i, -1) << endl;
    }
    return 0;
}

2.树的重心

对于一棵n个结点的无根树,找到一个点,使得把树变成以该结点为根的有根树时,最大子树结点数最小。

#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<stdio.h>
#include<string>
#include<vector>
using namespace std;
const int maxn = 1000 + 10;
int d[maxn];
int minNode;
int minbt;
vector<int>tree[maxn];
int n;

int dfs(int node, int parent) {
	d[node] = 1;
	int u = 0;
	for (int i = 0; i < tree[node].size(); i++) {
		int son = tree[node][i];
		if (son != parent) {
			dfs(son, node);
			d[node] += d[son];
			u = max(u, d[son]);//找出node的最大子树节点个数
		}
	}
	u = max(u, n - d[node]);//n-d[node]是parent的结点个数
	if (u < minbt) {
		minbt = u;
		minNode = node;
	}
}

int main()
{
	int kase;
	cin >> kase;
	while (kase--) {
		cin >> n;
		for (int i = 0; i < n; i++) {
			tree[i].clear();
		}
		for (int i = 0; i < n; i++) {
			int u, v;
			cin >> u >> v;
			tree[u].push_back(v);
			tree[v].push_back(u);
		}
		minNode = 0;
		minbt = 100000000;
		dfs(1, 0);
		cout << minNode << " " << minbt << endl;
	}
	return 0;
}

3.树的最长路径

对于一棵n个结点的无根树,找到一条最长路径,就是找两个结点,使得它们之间距离最大

可以用dfs先求一个结点的最远结点v,然后再求v结点的最远结点u,u-v就是最长距离。

动态规划是更新结点的左右两端距离

#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<stdio.h>
#include<string>
#include<vector>
using namespace std;
const int maxn = 1000 + 10;
int d[maxn];
int first[maxn], second[maxn];
vector<int>tree[maxn];
int n;
int res;
void dfs(int node, int parent) {
	d[node] = 0;
	int u = 0;
	for (int i = 0; i < tree[node].size(); i++) {
		int son = tree[node][i];
		if (son != parent) {
			dfs(son, node);
			if (first[son] + 1 >= first[node]) {//node结点的最长路径肯定不包括son的那枝子树
				first[node] = first[son] + 1;//first存储最长的路径/
				second[node] = first[node];//second存储次长的路径
			}
			else if(first[son]+1>second[node]){
				second[node] = first[son] + 1;
			}
		}
	}
	res = max(res, first[node] + second[node]);
}

int main()
{
	int kase;
	cin >> kase;
	while (kase--) {
		cin >> n;
		for (int i = 0; i < n; i++) {
			tree[i].clear();
		}
		for (int i = 0; i < n; i++) {
			int u, v;
			cin >> u >> v;
			tree[u].push_back(v);
			tree[v].push_back(u);
		}
		dfs(1, 0);
		cout << res << endl;
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值