Poj 3107 Godfather (DP_树形DP)

题目链接: 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,struct,tree,测试,null)