POJ-2378-Tree Cutting(树形DP)

Tree Cutting

After Farmer John realized that Bessie had installed a “tree-shaped” network among his N (1 <= N <= 10,000) barns at an incredible cost, he sued Bessie to mitigate his losses.

Bessie, feeling vindictive, decided to sabotage Farmer John’s network by cutting power to one of the barns (thereby disrupting all the connections involving that barn). When Bessie does this, it breaks the network into smaller pieces, each of which retains full connectivity within itself. In order to be as disruptive as possible, Bessie wants to make sure that each of these pieces connects together no more than half the barns on FJ.

Please help Bessie determine all of the barns that would be suitable to disconnect.

Input

  • Line 1: A single integer, N. The barns are numbered 1…N.

  • Lines 2…N: Each line contains two integers X and Y and represents a connection between barns X and Y.

Output

  • Lines 1…?: Each line contains a single integer, the number (from 1…N) of a barn whose removal splits the network into pieces each having at most half the original number of barns. Output the barns in increasing numerical order. If there are no suitable barns, the output should be a single line containing the word “NONE”.

Sample Input


10
1 2
2 3
3 4
4 5
6 7
7 8
8 9
9 10
3 8

Sample Output


3
8

解题思路:

相比上一篇博客的题目 HDU-2196(树形DP经典题) 传送门。更简单一些。
权值不再是边权,而是路径上点的个数。
题目意思给一棵树。求删掉哪些点(删点一个点意味着删掉所有和这个点连着的边),剩下的x课树的点的总数都不大于 n/2 。
那么在求解的时候,还是一样的套路,两遍DFS。
第一遍DFS求每个点的每一颗子树的节点数和。再记录一个总的节点数和。顺便标记一下这个点有没有可能删掉。如果有某棵子树的点数大于 n/2 那么肯定是不可以删掉的。
第二遍DFS求解答案。第三个参数就是上一层传下来的包含父节点在内的结点总数。可以剪枝。如果此时已经超过 n/2了那么就没必要往下了 因为再往下肯定都超过了。往下传递参数的时候,就把上一层的参数加上该节点的所有子树减去当前遍历的子树的点数和加1(因为他本身是一个点)。

AC代码:

//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <math.h>
#include <algorithm>
#include <map>
#include <queue>
#include <deque>
#define ios std::ios::sync_with_stdio(false)
#define int long long
using namespace std;
const int N = 3e5+10;
struct node{
    int val;	// 子树点数总和
    int flag;	// 有没有可能删掉
    vector<int> to;	 // 子树
    vector<int> wei; // 各个子树的点数和
}nodes[N];
int dp[N];
int n;

int dfs(int pos,int pre)
{
    int res = 0;
    nodes[pos].flag = 1;
    for(int i = 0 ; i < nodes[pos].to.size() ; i ++)
    {
        if(nodes[pos].to[i] == pre) continue;
        int tmp = dfs(nodes[pos].to[i],pos);
        nodes[pos].wei.push_back(tmp);
        res += tmp;
        if(tmp > n/2)  nodes[pos].flag = 0;
    }
    nodes[pos].val = res;
    return res + 1;
}


void dfs2(int pos,int pre,int sum)
{
    //cout<<pos<<" "<<sum<<" "<<nodes[pos].val<<endl;
    if(sum > n/2) return;
    int index = 0;
    for(int i = 0 ; i < nodes[pos].to.size() ; i ++)
    {
        if(nodes[pos].to[i] == pre) continue;
        dfs2(nodes[pos].to[i],pos,sum+1+nodes[pos].val-nodes[pos].wei[index]);
        index ++;
    }
    if(nodes[pos].flag)
        dp[pos] = 1;
}

signed  main()
{

    cin>>n;
    for(int i = 1; i < n ; i  ++)
    {
        int a,b;
        cin>>a>>b;
        nodes[a].to.push_back(b);
        nodes[b].to.push_back(a);
    }
    dfs(1,0);
    dfs2(1,0,0);
    int flag = 1;
    for(int i = 1; i <= n ; i ++)
    {
        if(dp[i])
        {
            flag = 0;
            cout<<i<<endl;
        }
    }
    if(flag)  cout<<"NONE"<<endl; // 写的时候忘记这行代码居然过了。 说明就没有不成立的数据
    return 0;
}

发布了104 篇原创文章 · 获赞 7 · 访问量 4046

猜你喜欢

转载自blog.csdn.net/qq_43461168/article/details/104211136