这道题是挺简单,求树上一条最长的路径(后来才知道这叫树的直径),而麻烦的是如何建树,这是这道题略恶心的地方。
数据的给出方式是每个节点给3个值(1~n),如果两个节点间有两个值相同,那么这两个点就是有一条边相连。题目中的描述什么凸多边形,三角形的顶点什么的一开始看确实被吓到了,其实就是两个三角形如果有公共边,那么这三角形代表的节点之间就有一条边,三角形的三个顶点就是前面所说的三个值。又因为整个图是凸多边形,也就是说三角形的顶点不会在内部出现,那么就是说不会有环的存在,而且整个图是一个连通的,又因为一共有n个顶点,会形成n-2个三角形,也就是说有n-2个节点,每个节点的三个值都是1~n之间的数,所以可以推得一共有n-3条边。n-2个节点,n-3条边,无环,连通,所以这是棵树。
那么我们怎么建树呢?——通过已有的每个节点的3个值。因为树边是需要两个值相等,所以我们需要记录两个值,如现在输入一个节点的三个值a,b,c,我们需要判断(a,b), (b,c), (a,c)是否存在,如果存在,就把存在的那个节点与当前结点连边,不存在则记录为存在。因为输入的三个值是无序的,而且边的存在性也不需要两个值顺序固定,所以我们要把a,b,c排序,避免明明存在(a,c)却因为当前输入顺序是(c,a)而判定为不存在。那么记录(a,b)这样的一个数对存在用二维数组会爆内存,不过我们可以想到STL里的MAP。定义一个<pair<int,int>, int>型的map,pair是数对,int是这个数对存在的节点,因为边是以相邻的三角形的公共边产生的,所以不用担心一个数对会出现3次或3次以上。
有了树,求直径:先以任意一个点为根BFS/DFS,找出距离最远的点,再以那个距离最远的点为根BFS/DFS,这次再求出来最远的点,这两个点的距离就是所求的最长路径了。BFS/DFS很好写,相当于裸题了。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <cstdlib>
#include <vector>
#define M 200002
using namespace std;
int n, p, d;
vector <int> G[M];
map <pair<int, int>, int> m;
pair <int, int> t;
void init(){
int a[3];
scanf("%d", &n);
for(int i = 1; i < n-1; i++){
scanf("%d %d %d", a, a+1, a+2);
sort(a, a+3);
t = make_pair(a[0], a[1]);
if(m[t]) G[i].push_back(m[t]), G[m[t]].push_back(i);
else m[t] = i;
t = make_pair(a[0], a[2]);
if(m[t]) G[i].push_back(m[t]), G[m[t]].push_back(i);
else m[t] = i;
t = make_pair(a[1], a[2]);
if(m[t]) G[i].push_back(m[t]), G[m[t]].push_back(i);
else m[t] = i;
}
}
void dfs(int u, int fa, int dis){
if(dis > d) p = u, d = dis;
for(int i = 0; i < G[u].size(); i++){
int v = G[u][i];
if(v == fa) continue;
dfs(v, u, dis+1);
}
}
int main()
{
init();
dfs(1, 0, 1);
dfs(p, 0, 1);
printf("%d", d);
}