惯例,先贴题目:
1021. Deepest Root (25)
A graph which is connected and acyclic can be considered a tree. The height of the tree depends on the selected root. Now you are supposed to find the root that results in a highest tree. Such a root is called the deepest root.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (<=10000) which is the number of nodes, and hence the nodes are numbered from 1 to N. Then N-1 lines follow, each describes an edge by given the two adjacent nodes' numbers.
Output Specification:
For each test case, print each of the deepest roots in a line. If such a root is not unique, print them in increasing order of their numbers. In case that the given graph is not a tree, print "Error: K components" where K is the number of connected components in the graph.
Sample Input 1:5 1 2 1 3 1 4 2 5Sample Output 1:
3 4 5Sample Input 2:
5 1 3 1 4 2 5 3 4Sample Output 2:
Error: 2 components
读完题目感觉难度不是非常大,总体上需要解决两个问题:
1、如何从图的某一点开始,求的最大深度;
2、如何识别连通子图。
对于第一个问题,我采用DFS的方式,依次遍历以每个结点为根的最大深度(用BFS更直观,这是码完了才意识到的= =)。对于第二个问题,通过一次DFS过程可以标记访问过的结点,如果仍有未访问的结点,那么连通子图的数量就加一。因此,整个算法就有两次DFS的过程,显然效率不够高,但最后居然让我AC了。最后一个case的时间是1300多ms,惊险啊。。下面贴代码:
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#define MAXN 10000
using namespace :: std;
int dfs(vector<int> g[MAXN], int * visited, int N, int start);
int notallvisited(int * visited, int N);
int main(){
int *hights, *visited, N, i, j, k, m, l;
scanf("%d", &N);
vector<int> graph[MAXN + 1];
hights = (int *)malloc(sizeof(int) * (N + 1));
visited = (int *)malloc(sizeof(int) * (N + 1));
for(i = 0; i < N - 1; i++){
scanf("%d %d", &j, &k);
graph[j].push_back(k);
graph[k].push_back(j);
visited[i] = 0;
}
visited[N - 1] = 0;
visited[N] = 0;
k = 0;
while(j = notallvisited(visited, N)){
k++;
dfs(graph, visited, N, j);
}
if(k > 1){
printf("Error: %d components", k);
}
else{
for(j = 1; j <= N; j++){
for(i = 1; i <= N; i++)visited[i] = 0;
hights[j] = dfs(graph, visited, N, j);
}
j = -1;
k = -1;
l = -1;
for(i = 1; i <= N; i++){
k = -1;
for(j = 1; j <= N; j++){
if(hights[j] > k){
m = j;
k = hights[j];
}
}
if(i == 1)
printf("%d\n", m);
else if(k == l)
printf("%d\n", m);
else
break;
l = hights[m];
hights[m] = -1;
}
}
return 0;
}
int dfs(vector<int> g[MAXN + 1], int * visited, int N, int start){
int max = 0, i, hight;
visited[start] = 1;
for(i = 0; i < g[start].size(); i++){
if(visited[g[start][i]])continue;
if((hight = dfs(g, visited, N, g[start][i])) > max)max = hight;
}
return max + 1;
}
int notallvisited(int * visited, int N){
int i = 1;
for(i = 1; i <= N && visited[i]; i++);
if(i > N)return 0;
return i;
}
还有一点要说的是,关于图的存储结构。最开始我用的邻接矩阵,定义了int graph[MAXN][MAXN](这里MAXN是10000),然后提交的时候所有的case都是段错误。不知道是不是堆栈溢出的原因,因为一个10000X10000的int二维数组,粗略一算占的内存要有400M,必然吃不消。后来改成了邻接表,问题就解决了。
稀疏矩阵尽量用邻接表存(建立一个vector<int>的数组),稠密矩阵用邻接矩阵比较合适。