【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;
}
posted @ 2018-04-27 08:48  Maxwei_wzj  阅读(150)  评论(0编辑  收藏  举报