Written with StackEdit.
Description
到了难得的暑假,为了庆祝小白在数学考试中取得的优异成绩,小蓝决定带小白出去旅游~~
经过一番抉择,两人决定将(T)国作为他们的目的地。(T)国的国土可以用一个凸(N)边形来表示,(N)个顶点表示(N)个入境/出境口。T国包含(N-2)个城市,每个城市都是顶点均为(N)边形顶点的三角形(换而言之,城市组成了关于(T)国的一个三角剖分)。两人的旅游路线可以看做是连接(N)个顶点中不相邻两点的线段。
为了能够买到最好的纪念品,小白希望旅游路线上经过的城市尽量多。作为小蓝的好友,你能帮帮小蓝吗?
Input
每个输入文件中仅包含一个测试数据。
第一行包含两个由空格隔开的正整数(N),(N)的含义如题目所述。
接下来有(N-2)行,每行包含三个整数(p,q,r),表示该城市三角形的三个顶点的编号((T)国的(N)个顶点按顺时间方向从(1)至(N)编号)。
Output
输出文件共包含(1)行,表示最多经过的城市数目。(一个城市被当做经过当且仅当其与线路有至少两个公共点)
Sample Input
6
1 2 4
2 3 4
1 4 5
1 5 6
Sample Output
4
HINT
(4<=N<=200000)
Solution
- 将每个三角形看成一个点.相邻的两个三角形之间连边.
- 注意到三角剖分中,一定需要剖(N-3)次,每剖一次,图中多出一条边,这条边只能连接一对三角形.(节点).
- 那么这个图共有(N-2)个点,(N-3)条边,且是连通的.
- 那么所求的答案即为树的直径.
#include<bits/stdc++.h>
using namespace std;
typedef long long LoveLive;
typedef pair<int,int> pii;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
{
fh=-1;
jp=getchar();
}
while (jp>='0'&&jp<='9')
{
out=out*10+jp-'0';
jp=getchar();
}
return out*fh;
}
const int MAXN=2e5+10;
map<pii,int> s;
map<pii,int>::iterator it;
int n;
int cnt=0,head[MAXN];
int nx[MAXN<<1],to[MAXN<<1];
inline void add(int u,int v)
{
++cnt;
to[cnt]=v;
nx[cnt]=head[u];
head[u]=cnt;
}
inline void ins(int u,int v)
{
add(u,v);
add(v,u);
}
int dep[MAXN],q[4];
void opr(int a,int b,int i)
{
it=s.find(make_pair(q[a],q[b]));
if(it!=s.end())
ins(it->second,i),s.erase(it);
else
s[make_pair(q[a],q[b])]=i;
}
void dfs(int u,int fa)
{
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(v==fa)
continue;
dep[v]=dep[u]+1;
dfs(v,u);
}
}
int getd()
{
int res=-1,rt;
dep[1]=1;
dfs(1,0);
for(int i=1;i<=n-2;++i)
if(dep[i]>res)
res=dep[i],rt=i;
dep[rt]=1;
dfs(rt,0);
for(int i=1;i<=n;++i)
res=max(res,dep[i]);
return res;
}
int main()
{
n=read();
for(int i=1;i<=n-2;++i)
{
q[1]=read();
q[2]=read();
q[3]=read();
sort(q+1,q+4);
opr(1,2,i);
opr(1,3,i);
opr(2,3,i);
}
int ans=getd();
printf("%d
",ans);
return 0;
}