[ZJOI2012] 旅游
题目描述
到了难得的暑假,为了庆祝小白在数学考试中取得的优异成绩,小蓝决定带小白出去旅游~~经过一番抉择,两人决定将T国作为他们的目的地。T国的国土可以用一个凸N边形来表示,N个顶点表示N个入境/出境口。T国包含N-2个城市,每个城市都是顶点均为N边形顶点的三角形(换而言之,[b]城市组成了关于T国的一个三角剖分[/b])。[b]两人的旅游路线可以看做是连接N个顶点中不相邻两点的线段[/b]。
为了能够买到最好的纪念品,小白希望旅游路线上经过的城市尽量多。作为小蓝的好友,你能帮帮小蓝吗?
输入输出格式
输入格式:
每个输入文件中仅包含一个测试数据。
第一行包含两个由空格隔开的正整数N,N的含义如题目所述。
接下来有N-2行,每行包含三个整数 p,q,r,表示该城市三角形的三个顶点的编号(T国的N个顶点按顺时间方向从1至n编号)。
输出格式:
输出文件共包含1行,表示最多经过的城市数目。([b]一个城市被当做经过当且仅当其与线路有至少两个公共点[/b])
输入输出样例
输入样例#1: 复制
6
1 2 4
2 3 4
1 4 5
1 5 6
输出样例#1: 复制
4
说明
对于20%的数据, n<=2000
对于100%的数据, 4<=n<=200000
Solution
一句话题意,三个边围成一个城市,拥有共同边的城市可以互相到达。
显然,这个图可以建成一棵树,拥有共同城市的建边,用map存下,这条边有没有出现过,求树上最长路,树的直径,没了,一道水题。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
typedef pair<int,int> pr;
map<pr,int> q;
struct node
{
int to,next,w;
}a[2001010];
int len,last[501010],d[501000];
void add(int a1,int a2,int a3)
{
a[++len].to=a2;
a[len].w=a3;
a[len].next=last[a1];
last[a1]=len;
}
void dfs(int x,int father)
{
for(int i=last[x];i;i=a[i].next)
{
int to=a[i].to;
if(to==father) continue;
d[to]=d[x]+a[i].w;
dfs(to,x);
}
}
int main()
{
int n,x,y,z;
cin>>n;
for(int i=1;i<=n-2;i++)
{
scanf("%d%d%d",&x,&y,&z);
if(x>y) swap(x,y);
if(y>z) swap(y,z);
if(x>y) swap(x,y);
int s=q[pr(x,y)];
if(s) add(i,s,1),add(s,i,1);
else q[pr(x,y)]=i;
s=q[pr(x,z)];
if(s) add(i,s,1),add(s,i,1);
else q[pr(x,z)]=i;
s=q[pr(y,z)];
if(s) add(i,s,1),add(s,i,1);
else q[pr(y,z)]=i;
}
dfs(1,0);
int l=0,r=0;
for(int i=1;i<=n;i++) if(d[i]>d[l]) l=i;
memset(d,0,sizeof(d));
dfs(l,0);
for(int i=1;i<=n;i++) if(d[i]>d[r]) r=i;
cout<<d[r]+1<<endl;
}