1. 程式人生 > >P3174 [HAOI2009]毛毛蟲

P3174 [HAOI2009]毛毛蟲

printf reg div radius == stdio.h 最長鏈 sample ()

題目描述

對於一棵樹,我們可以將某條鏈和與該鏈相連的邊抽出來,看上去就象成一個毛毛蟲,點數越多,毛毛蟲就越大。例如下圖左邊的樹(圖 1 )抽出一部分就變成了右邊的一個毛毛蟲了(圖 2 )。

技術分享圖片

輸入輸出格式

輸入格式:

在文本文件 worm.in 中第一行兩個整數 N , M ,分別表示樹中結點個數和樹的邊數。

接下來 M 行,每行兩個整數 a, b 表示點 a 和點 b 有邊連接( a, b ≤ N )。你可以假定沒有一對相同的 (a, b) 會出現一次以上。

輸出格式:

在文本文件 worm.out 中寫入一個整數 , 表示最大的毛毛蟲的大小。

輸入輸出樣例

輸入樣例#1:
復制
13 12 
1 2 
1 5 
1 6 
3 2 
4 2 
5 7 
5 8 
7 9 
7 10 
7 11 
8 12 
8 13 
輸出樣例#1: 復制
11

說明

40% 的數據, N ≤ 50000

100% 的數據, N ≤ 300000


基本上就是要找樹的直徑,只不過是這道題還要加上距離為1的點。

但是其實是一樣的,一共有兩種情況:

1.一個節點x其子樹中最大的兩條毛毛蟲大小之和

技術分享圖片

2.一個葉子節點到根節點

技術分享圖片

與求直徑不同之處在於更新一個點子樹中的最長鏈時還要加上他的兄弟個數

只要在每一次判斷的時候變成f[i]=max(f[t])+size[i]

#include<iostream>
#include<stdio.h>

using namespace std;

int k,i,m,n,j,l,a[300004],g,h,cnt,ver[1000005],nex[1000005],head[1000005],f[1000005],w,s[1000005];

void add(int x,int y)
{
    cnt+=1;
    ver[cnt]=y;
    nex[cnt]=head[x];
    head[x]=cnt;
}

void dfs(int x,int y)
{
    int ans=-0x7fffffff;
    for(int i=head[x];i;i=nex[i])
    {
        int t=ver[i];
        if(t==y) continue;
        dfs(t,x);
        k=max(k,f[x]+f[t]+s[x]-1);
        if(f[t]>f[x]) f[x]=f[t];
    }
    if(s[x]<=2) f[x]+=1;
    else f[x]+=s[x]-1;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++) 
    {
        scanf("%d%d",&g,&h);
        s[g]+=1; s[h]+=1;
        add(g,h);
        add(h,g);
    }
    dfs(1,0);
    printf("%d",max(k,f[1]));
}

P3174 [HAOI2009]毛毛蟲