读书人

poj1655-又是一路简单而又纠结的题目

发布时间: 2012-11-07 09:56:10 作者: rapoo

poj1655-又是一道简单而又纠结的题目

题目很好理解,就是去掉树上的一个节点,看看剩下的子树中最大的是多少,然后在这些最大值中求一个最小值,如果有多个点都是最小值,那么找一个序号最小的节点。

输出节点号,和最小值。

经过简单分析,dfs深度优先搜索可以解决,只需要求出每个节点下子树的总结点个数即可。

举例说明:

设有一棵树20个节点,其中有一个节点为u,u有两个孩子节点,设u以下有10个节点,两个孩子分别有6和4个节点,那么对于u来说,最大是多少,应该是20 - 10,6,4中的最大的也就是10.这样等把所有节点的最大值求出后,再求1-n中的最小值,输出该点以及最小值即可。

算法就是dfs,计算出每个节点下的总数,然后保留本节点下的孩子节点子树中的最大值,然后和自己的祖先节点比较求出最大值,最后枚举最小值。

这题wa了很多次,感觉dfs没问题,后来确实发现时建图的问题。一定要建一个双向图,因为树是无向的。

开始我只按照题目给的建了一个图,

如果碰到下面的例子,比如有5个点,1一圈有四个点

也就是

5

4 1

3 1

2 1

5 1

这样的话当搜索到1时就终止了,没法通过1搜到其他点。所以建双向,然后判是否走过就行了。

纠结了好久。。。。

下面是代码:

#include <stdio.h>#include <stdlib.h>#include <string.h>#define Max(a,b) (a>b?a:b)#define Min(a,b) (a<b?a:b)#define  nMax 20010struct Edge{int v;int next;}edge[2 * nMax];//保存双向图int preEdge[nMax];//同一个起点的上一条边int n;bool flag[nMax];int childNum[nMax];//每个节点下的节点总数int min;int childMax[nMax];//每个节点去掉后其他子树最多点数int dfs(int root){flag[root] = true;int p = preEdge[root];//以root为起点的边的标示也就是edge的下标while (p){int v = edge[p].v;//root连接的点if (!flag[v]){childNum[root] += dfs(v);//求root点下的所有节点childMax[root] = Max(childNum[edge[p].v], childMax[root]);//求root点下孩子节点中的最大值}p = edge[p].next;//以root为起点的上一条边}childMax[root] = Max(n - childNum[root], childMax[root]);//root下孩子节点中的最大值和祖先节点总数的最大值作为本节点的最大值return childNum[root];//返回本节点的总数}int  main(){int t;int u, v;while (scanf("%d", &t) != EOF){while (t --){memset(preEdge, 0, sizeof(preEdge));memset(flag, false, sizeof(flag));min = 0x0FFFFFFF;scanf("%d", &n);for (int i = 1; i < 2 * (n - 1); i += 2)//建图{scanf("%d %d", &u, &v);edge[i].v = v;edge[i].next = preEdge[u];preEdge[u] = i;edge[i + 1].v = u;edge[i + 1].next = preEdge[v];preEdge[v] = i + 1;}if (n == 1){printf("1 0\n");continue;}//memset(childNum, 0, sizeof(childNum));for (int i = 1; i <= n; ++ i){childNum[i] = 1;childMax[i] = -1;}dfs(1);//dfsint mMin = 0x0FFFFFFF, k;for (int i = 1; i <= n; ++ i)//求最小值{if (mMin > childMax[i]){k = i;mMin = childMax[i];}}printf("%d %d\n", k, mMin);}}return 0;}

读书人网 >其他相关

热点推荐