题目链接:
http://poj.org/problem?id=3107
题目大意 :黑手党情况错综复杂,关系相当于一棵n个节点的树,去掉某个节点后,树被分成很多块,分出来的块最小他便是Goldfather,Goldfather可能有多个,升序输出。
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
题目大意 :黑手党情况错综复杂,关系相当于一棵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原创,但可以转载,因为我们是兄弟。