poj 1655 树状dp

#include<iostream>
#include<cstdio>
#include<string.h>
#include<cstring>
#include<string>
#include<algorithm>

using namespace std;

const int maxn = 20010;
const int inf = 0x1fffffff;
typedef struct EDGE{
	int node,Next;
}Edge;
Edge edge[maxn<<1];
int balance[maxn],recordnode[maxn],nodenum[maxn],t,n;
bool visit[maxn];
int cntEdge = 0;
inline void addEdge(int n1,int n2){
	edge[cntEdge].node = n1; edge[cntEdge].Next = recordnode[n2]; recordnode[n2] = cntEdge++;
	edge[cntEdge].node = n2; edge[cntEdge].Next = recordnode[n1]; recordnode[n1] = cntEdge++;
}
int dfs(int id){
	int ans = 0, sum = 0,i;
	visit[id] = 1;
	for(i = recordnode[id]; i != -1; i = edge[i].Next){
		int nodeid = edge[i].node;
		if(!visit[nodeid]){
		    int t = dfs(nodeid);
			sum += t;
			if(ans < t)
				ans = t;
		}
	}
	//ans为以id的所有叶结点为根的子树所含结点的最大值
	nodenum[id] = sum + 1;
	int t = n - nodenum[id];  //删掉以id为根的子树后余下的所有结点
	if(ans < t){
		ans = t;
	}
	balance[id] = ans;
	return nodenum[id];
}

int main(){
	int i;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		cntEdge = 0;
		memset(visit,0,sizeof(visit));
		memset(nodenum,0,sizeof(nodenum));
		memset(recordnode,-1,sizeof(recordnode));
		int node1,node2;
		for(i = 1; i < n; ++i){
			scanf("%d%d",&node1,&node2);
			addEdge(node1,node2);
		}
		dfs(1);
		int ans,index = -1;
		bool ismax;
		ans = inf;
		for(i = 1; i <= n; ++i){
			ismax = ans > balance[i];
			ans = ismax?balance[i]:ans;
			index = ismax?i:index;
		}
		printf("%d %d\n",index,ans);
	}
	return 0;
}

题目大意:

给定一颗树,对每个结点,其balance为去掉这个结点后产生的森林中各个子树的最大节点数,求所有节点中balance值最小的那个

解题思路:

设n为树中的结点总数,num[i]表示以结点i为根结点的子树的节点数

balance[k] = max(n-num[k],num[j1],num[j2]...num[jl])(j1,j2,...,jl是k的所有子树编号)

因为题目中给定的边的顺序未必是树的构建顺序,所以要用dfs+标记visit的方法来确定树中的根和子结点的关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值