zoukankan      html  css  js  c++  java
  • NOIP模拟 拆网线

    题目大意:

    给一颗n个节点的树,保留最少的边,使得每个连通块的大小都大于等于2,并且连通块的点数和等于k.

    题目分析:

    要想留下的边数最少,就要尽量多的选择单独的边,这里就要贪心:尽可能多的选择单独的边。 如果选出的边*2大于等于了k,就直接根据k的奇偶返回答案。如果不够,就将剩下的点挂在每一条单链上。
    明确思路,只要求出最多的单独的边问题就迎刃而解:dp[i][0]表示i节点不向儿子连边,其子树中最多的单独的边,dp[i][1]表示i节点向某一个儿子连边其子树中最多的单独的边。

    [dp[i][0] = sum{dp[son[i]][1]} ]

    [dp[i][1] = (sum{dp[son[i]][1]}) + max{-dp[son[i]][1] + dp[son[i]][0]} + 1 ]

    code

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 100050
    namespace IO{
    	inline int read(){
    		int i = 0, f = 1; char ch = getchar();
    		for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
    		if(ch == '-') f = -1, ch = getchar();
    		for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
    		return i * f;
    	}
    	inline void wr(int x){
    		if(x < 0) x = -x, putchar('-');
    		if(x > 9) wr(x / 10);
    		putchar(x % 10 + '0');
    	} 
    }using namespace IO;
    int T, n, k, dp[maxn][2];
    vector<int> adj[maxn];
    
    inline void DP(int x, int f){
    //	cout<<x<<"!!!";
    	int maxx = 0;
    	for(int i = adj[x].size() - 1; i >= 0; i--){
    		int v = adj[x][i];
    		if(v == f) continue;
    		DP(v, x);
    		dp[x][0] += dp[v][1];
    		maxx += dp[v][1];
    	}
    	for(int i = adj[x].size() - 1; i >= 0; i--){
    		int v = adj[x][i];
    		if(v == f) continue;
    		dp[x][1] = max(dp[x][1], maxx - dp[v][1] + dp[v][0] + 1); 
    	}
    //	cout<<x<<" "<<dp[x][1]<<" "<<dp[x][0]<<endl;
    }
    
    int main(){
    	freopen("h.in",  "r", stdin);
    	scanf("%d", &T);
    	while(T--){
    		for(int i = 1; i <= n; i++) adj[i].clear();
    		memset(dp, 0, sizeof dp);
    		n = read(), k = read();
    		for(int i = 1; i < n; i++){
    			int x = read();
    			adj[x].push_back(i + 1), adj[i + 1].push_back(x);
    		}
    		DP(1, 0);
    //		continue;
    		if(max(dp[1][0], dp[1][1]) * 2 >= k){
    			if(k & 1){
    				wr((k - 3) / 2 + 2), putchar('
    ');
    			}
    			else{
    				wr(k / 2), putchar('
    ');
    			}
    		}
    		else wr(max(dp[1][0], dp[1][1]) + k - 2 * (max(dp[1][0], dp[1][1]))), putchar('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    pe文件结构
    dll
    术语
    创建内存映射文件
    函数的调用约定
    串口
    linux 之 tcpdump
    linux 之程序管理
    perl 之eval
    2020-10-27_组合快捷键
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7716721.html
Copyright © 2011-2022 走看看