• 删边


    Description
      给出N个点,N-1条边的连通图.
      现要求删除一条边,使得连通块的直径总和最大.所谓连通块的直径是指连通块中最远两点之间的距离。
         问:直径总和最大是多少?

    Input
      文件名为 delete.in
      第一行正整数N.
      接下来N-1行.每行两个数,A,B,LEN表示A,B(1<=A,B<=N)有一条长度为Len(1<=Len<=1000)的边连接着.

    Output
      文件名为 delete.out
      一个数Ans.直径总和的最大值.

    Sample Input
    10
    2 1 982
    3 1 169
    4 1 934
    5 1 325
    6 1 735
    7 1 675
    8 2 302
    9 3 450
    10 5 173

    Sample Output
    2668

    Data Constraint

    Hint
    【数据范围】
      30% N<=100
      70% N<=5000
      100% N<=100000
    .
    .
    .
    .
    .
    .

    分析

    我们要预处理出每一棵子树的直径和子树中的最远点,次远点和子树中过x的最长链、次长链和次次长链
    那么考虑删去一条边后直径有哪几种情况
    ①在x的子树里
    ②在x上面的联通块的直径
    ③x子树没被删去的最远点与x上方最远点的和
    ④在x不同子树上最远的点的和

    考虑一下怎么求:
    ①预处理得出
    ②在递归时可以记录当前经过联通块的最大值
    ③x子树里的在预处理里已经求出来,那么不在x子树里的也就是递归经过x的最长链
    ④也就是在x子树里不含被删子树的最远点和次远点
    .
    .
    .
    .
    .

    程序:
    #include<iostream>
    using namespace std;
    int m[2][100001][4],d[2][100001][4],fa[100001],head[100001],dis[100001],ans,n,cnt;
    
    struct edge 
    { 
        int to,from,v; 
    }rp[200001];
    
    void insert(int x,int y,int z) 
    { 
        rp[++cnt].to=y;rp[cnt].v=z;rp[cnt].from=head[x];head[x]=cnt; 
    }
    
    void dfs(int x)
    {
        for (int i=head[x];i;i=rp[i].from)
        {
            int w=rp[i].to;
            if (w!=fa[x])
            {
                fa[w]=x;
                dfs(w);
                dis[x]=max(dis[x],dis[w]);
                if (dis[w]>m[0][x][1])
                {
                    m[0][x][2]=m[0][x][1];
                    m[0][x][1]=dis[w];
                    d[0][x][1]=w;
                } else 
                if (dis[w]>m[0][x][2]) m[0][x][2]=dis[w];
                int v=m[1][w][1]+rp[i].v;
                if (v>m[1][x][1])
                {
                    m[1][x][3]=m[1][x][2];
                    m[1][x][2]=m[1][x][1];
                    m[1][x][1]=v;
                    d[1][x][2]=d[1][x][1];
                    d[1][x][1]=w;
                } else
                if (v>m[1][x][2])
                {
                    m[1][x][3]=m[1][x][2];
                    m[1][x][2]=v;
                    d[1][x][2]=w;
                } else 
                if (v>m[1][x][3]) m[1][x][3]=v;
            }
        }
        dis[x]=max(m[1][x][1]+m[1][x][2],m[0][x][1]);
    }
    
    void find(int x,int a,int b)        
    {
        int m1,m2,m3;
        if (x!=1) ans=max(ans,dis[x]+a);
        for (int i=head[x];i;i=rp[i].from)
        {
            int v=rp[i].to;
            if (v!=fa[x])
            {
                if (d[1][x][1]==v)
                {
                    m1=m[1][x][2];
                    m2=m[1][x][2]+m[1][x][3];
                } else
                {
                    m1=m[1][x][1];
                    if (d[1][x][2]==v) m2=m[1][x][1]+m[1][x][3]; else m2=m[1][x][1]+m[1][x][2];
                }
                if (d[0][x][1]==v) m3=m[0][x][2]; else m3=m[0][x][1];
                find(v,max(max(a,m3),max(m1+b,m2)),max(b,m1)+rp[i].v);
            }
        }
    }
    int main()
    {
        cin>>n;
        for (int i=1;i<=n-1;i++)
        {
            int x,y,z;
            cin>>x>>y>>z;
            insert(x,y,z); 
            insert(y,x,z);
        }
        dfs(1);
        find(1,0,0);
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    自我介绍
    注册表代码
    圣杯布局
    css的颜色设置
    c语言:第二次作业,循环结构
    c语言:第一次作业,分支,顺序结构
    C语言博客作业03函数
    第零次作业
    用JSP判断输入是质数还是非质数
    用JSP完成输入整形,单精度浮点数,双精度浮点数
  • 原文地址:https://www.cnblogs.com/YYC-0304/p/9499936.html
Copyright © 2020-2023  润新知