【BZOJ2657】旅游(ZJOI2012)-对偶图+树形DP
测试地址:旅游
做法:本题需要用到对偶图+树形DP。
注意到,凸多边形的三角剖分的对偶图是一棵树,这是显然的,因为不可能存在环,而且图一定连通。又注意到,一条线段所经过的一些三角形,它们在对偶图上是一条链,这个也是显然的。而每条链一定对应一条或多条旅游路线,因为凸多边形三角剖分中,一些三角形拼起来一定还是凸多边形,所以一定能找到一条路线对应这条链。得出上述结论后,直接对对偶图求直径即可。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
int n,tot=0,first[200010]={0},toted=0;
int mx[200010],ans=0;
struct forsort
{
int a,b,id;
}f[400010];
struct edge
{
int v,next;
}e[400010];
bool cmp(forsort a,forsort b)
{
if (a.a!=b.a) return a.a<b.a;
else return a.b<b.b;
}
void insert(int a,int b,int id)
{
if (a>b) swap(a,b);
if ((a==1&&b==n)||(a+1==b)) return;
f[++tot].a=a,f[tot].b=b;
f[tot].id=id;
}
void insertedge(int a,int b)
{
e[++toted].v=b;
e[toted].next=first[a];
first[a]=toted;
}
void dp(int v,int fa)
{
int Mx=0,Smx=0;
for(int i=first[v];i;i=e[i].next)
if (e[i].v!=fa)
{
dp(e[i].v,v);
if (mx[e[i].v]>Mx)
{
Smx=Mx;
Mx=mx[e[i].v];
}
else if (mx[e[i].v]>Smx)
Smx=mx[e[i].v];
}
ans=max(ans,Mx+Smx+1);
mx[v]=Mx+1;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n-2;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
insert(a,b,i);
insert(a,c,i);
insert(b,c,i);
}
sort(f+1,f+tot+1,cmp);
for(int i=1;i<=tot;i++)
if (i>1&&f[i].a==f[i-1].a&&f[i].b==f[i-1].b)
{
insertedge(f[i].id,f[i-1].id);
insertedge(f[i-1].id,f[i].id);
}
dp(1,0);
printf("%d",ans);
return 0;
}