• hihocoder-1453-Rikka with Tree


    #Hihocoder 1453 : Rikka with Tree

    时间限制:10000ms
    单点时限:1000ms
    内存限制:256MB
     
    source: https://hihocoder.com/problemset/problem/1453

    描述

    众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:

    勇太有一棵 n 个节点的以1为根的有根树。现在他可以对这棵树进行若干次操作,每一次操作可以选择树上的一个点然后删掉这个点和它的儿子之间的所有边。

    现在勇太想要知道对于每一个 k ∈ [1, n],最少需要多少次操作才能让图中恰好存在 k 个联通块。

    当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?

    输入

    第一行输入一个正整数 n (n ≤ 3000)。

    第二行输入 n-1 个整数 fi 表示 i+1 号点的父亲,保证 1 ≤ fi ≤ i

    输出

    输出 n 个整数,第 i 个数表示 k=i 时的答案,如果无法让图中恰好存在 k 个联通块,则输出-1。

    样例输入
    6
    1 2 1 1 2
    样例输出
    0 -1 1 1 -1 2

    题解:

    每减去一个节点,产生的联通块的数量就是该节点的孩子数量。  所以, 实质上是一道单重背包问题的变形。 

    #include <iostream> 
    #include <cstdio> 
    #include <cstring> 
    #include <cstdlib> 
    using namespace std; 
    const int MAXN = 3005; 
    
    int n, root[MAXN], dp[MAXN]; 
    
    int main(){
    	freopen("in.txt", "r", stdin);
    
    	int x, max_x, tmp; 
    	scanf("%d", &n);
    	memset(root, 0, sizeof(root));  
    	max_x = 0; 
    	for(int i=1; i<n; ++i) {
    		scanf("%d", &x); 
    		root[x]++;  
    		if(max_x < x){
    			max_x = x; 
    		}
    	}
    	memset(dp, 0, sizeof(dp)); 
    	dp[0] = 1; 
    	for(int i=max_x; i>=1; --i){
    		if(root[i] != 0){
    			for(int j=n; j>=root[i]; --j){
    				if(dp[j-root[i]] != 0){
    					if(dp[j] != 0){
    						dp[j] = min(dp[j], dp[j-root[i]] + 1); 
    					}  else {
    						dp[j] = dp[j-root[i]] + 1; 
    					}
    				}
    			}
    		}
    	}
    	for(int i=0; i<n; ++i){
    		if(dp[i]){
    			printf("%d ", dp[i]-1);
    		}else{
    			printf("%d ", -1 );
    		}
    	}
    	printf("
    ");
    
    	return 0; 
    }
    

      

  • 相关阅读:
    python判断字典中key是否存在
    获取redis中所有的key,清空整个 Redis 服务器的数据
    python redis模块详解
    Windows中redis的下载及安装、设置
    .htaccess
    python介绍
    vi和vim
    其他
    Linux系统相关命令
    Linux用户权限常见命令
  • 原文地址:https://www.cnblogs.com/zhang-yd/p/6220534.html
Copyright © 2020-2023  润新知