Poj 3107 Godfather (DP_树形DP)

本文介绍了一道经典的树形DP题目——POJ 3107 Goldfather的解题思路及实现代码。通过模拟操作,利用深搜算法计算每个节点作为根时,分割出的子树中最大子树的节点数,以此来确定Goldfather。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接: http://poj.org/problem?id=3107

题目大意 :黑手党情况错综复杂,关系相当于一棵n个节点的树,去掉某个节点后,树被分成很多块,分出来的块最小他便是Goldfather,Goldfather可能有多个,升序输出。

解题思路:因为期末考试,好多天没做题,做题的那种感觉都差点找不到,幸好做的第一题便是水题。做每件事投入了都会有一种状态,如果这种状态能一直保持,那么做事的效率将事半功倍,吼吼,保持到年底区域赛。言归正传,本题是简单的树形dp,因为要分块,把这棵树看成有序树,那么分成的块就是父节点所在的一块加每个子节点所在的块。决定是不是Goldfather的为这些块中的最大块。那么我们模拟这个操作,先让1为根,然后算他们的子节点个数多少。然后再一次深搜,把每个节点的最大块找出来,更新答案即可。


测试数据:
6
1 2
2 3
2 5
3 4
3 6


7
1 2
2 3
2 5
2 7
3 4
3 6


7
1 2
1 3
1 4
1 5
1 6

1 7


代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define MAX  110000
#define min(a,b) (a)<(b)?(a):(b)
#define max(a,b) (a)>(b)?(a):(b)


struct node {

	int v;
	node *next;
}*head[MAX],tree[MAX];
int n,ptr,dp[MAX];
int ans,res[MAX],tot;

void Initial(){
	//初始化
	ptr = 1,ans = 2147483647;
	memset(dp,0,sizeof(dp));
	memset(head,NULL,sizeof(head));
}
void AddEdge(int x,int y) {
	//插入一条边
	tree[ptr].v = y;
	tree[ptr].next = head[x],head[x] = &tree[ptr++];
	tree[ptr].v = x;
	tree[ptr].next = head[y],head[y] = &tree[ptr++];
}

void Dfs(int son,int pa) {
	//第一次深搜,记录每个节点的子节点数
	node *p = head[son];
	dp[son] = 1;
	while (p != NULL) {

		if (p->v != pa) 
			Dfs(p->v,son),dp[son] += dp[p->v];
		p = p->next;
	}
}
void Tree_DP(int son,int pa) {

	int mmax = 0,sum = 0,sumpa = 0;
	node *p = head[son];

	//算向上和向下的节点数
	while (p != NULL) {
	
		if (p->v != pa) {
			
			Tree_DP(p->v,son);
			mmax = max(mmax,dp[p->v]);
		}
		p = p->next;
	}
	//更新答案
	mmax = max(n-dp[son],mmax);
	if (mmax < ans) {

		tot = 1,ans = mmax;
		res[tot] = son;
	}
	else if (mmax == ans) {

		tot++;
		res[tot] = son;
	}
}


int main()
{
	int i,j,k,a,b;


	while (scanf("%d",&n) != EOF) {
		
		Initial();
		for (i = 1; i < n; ++i)
			scanf("%d%d",&a,&b),AddEdge(a,b);


		Dfs(1,0);
		Tree_DP(1,0);
		sort(res+1,res+tot+1);
		for (i = 1; i <= tot; ++i)
			printf("%d%c",res[i],i==tot?'\n':' ');
	}
}


本文ZeroClock原创,但可以转载,因为我们是兄弟。

内容概要:本文详细介绍了哈希表及其相关概念和技术细节,包括哈希表的引入、哈希函数的设计、冲突处理机制、字符串哈希的基础、哈希错误率分析以及哈希的改进与应用。哈希表作为一种高效的数据结构,通过键值对存储数据,能够快速定位和检索。文中讨论了整数键值和字符串键值的哈希方法,特别是字符串哈希中的多项式哈希及其优化方法,如双哈希和子串哈希的快速计算。此外,还探讨了常见的冲突处理方法——拉链法和闭散列法,并提供了C++实现示例。最后,文章列举了哈希在字符串匹配、最长回文子串、最长公共子字符串等问题中的具体应用。 适合人群:计算机科学专业的学生、算法竞赛选手以及有一定编程基础并对数据结构和算法感兴趣的开发者。 使用场景及目标:①理解哈希表的工作原理及其在各种编程任务中的应用;②掌握哈希函数的设计原则,包括如何选择合适的模数和基数;③学会处理哈希冲突的方法,如拉链法和闭散列法;④了解并能运用字符串哈希解决实际问题,如字符串匹配、回文检测等。 阅读建议:由于哈希涉及较多数学知识和编程技巧,建议读者先熟悉基本的数据结构和算法理论,再结合代码实例进行深入理解。同时,在实践中不断尝试不同的哈希策略,对比性能差异,从而更好地掌握哈希技术。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值