题目描述
对于一棵树,我们可以将某条链和与该链相连的边抽出来,看上去就象成一个毛毛虫,点数越多,毛毛虫就越大。
输入输出格式
输入格式:
在文本文件 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
又是一道省选题。。。
题解
题目要我们找一条链,使链上的点数和与它相连的边数最大神TM毛毛虫
显然是一道树形DP题。先用一个数组t表示每个点所连的边数,f[i]表示从i的子树中一点到i的毛毛虫大小,为了方便,我把i当成毛,设v为它儿子,则f[i]=max{f[v]+t[u]-1},你可能会想,怎么统计答案?
我们设ma1为u所有儿子vk中最大的f[vk],ma2为次大的f[vk],ans=max{ma1+ma2+t[u]-1};
常数巨大的丑陋代码
# include <stdio.h>
# include <stdlib.h>
# include <iostream>
# include <string.h>
# include <math.h>
using namespace std;
# define IL inline
# define RG register
# define UN unsigned
# define ll long long
# define rep(i, a, b) for(RG int i = a; i <= b; i++)
# define per(i, a, b) for(RG int i = b; i >= a; i--)
# define uev(e, u) for(RG int e = ft[u]; e != -1; e = edge[e].nt)
# define mem(a, b) memset(a, b, sizeof(a))
# define max(a, b) ((a) > (b)) ? (a) : (b)
# define min(a, b) ((a) < (b)) ? (a) : (b)
IL int Get(){
RG char c = '!'; RG int num = 0, z = 1;
while(c != '-' && (c > '9' || c < '0')) c = getchar();
if(c == '-') z = -1, c = getchar();
while(c >= '0' && c <= '9') num = num * 10 + c - '0', c = getchar();
return num * z;
}
const int MAXN = 300001, INF = 2147483647;
struct Edge{
int to, nt;
} edge[MAXN << 1];
int n, cnt, ft[MAXN], m, ans, t[MAXN], f[MAXN];
IL void Add(RG int u, RG int v){
edge[cnt] = (Edge){v, ft[u]}; ft[u] = cnt++; t[u]++;
}
IL void Dfs(RG int u, RG int fa){
RG int ma1 = 0, ma2 = 0;
uev(e, u){
RG int v = edge[e].to;
if(v == fa) continue;
Dfs(v, u);
if(f[v] > ma1) ma2 = ma1, ma1 = f[v];
else if(f[v] > ma2) ma2 = f[v];
f[u] = max(f[u], f[v] + t[u] - 1);
}
ans = max(ans, ma1 + t[u] - 1 + ma2);
}
int main(){
mem(ft, -1);
n = Get(); m = Get();
rep(i, 1, n) f[i] = 1;
rep(i, 1, m){
RG int u = Get(), v = Get();
Add(u, v); Add(v, u);
}
Dfs(1, 0);
printf("%d
", ans);
return 0;
}