是真的一道难题啊,确实连dp应该怎样表示都没有想到。这里的突破点是N不是很大,的复杂度是可以接受的,并且
数组的内存也是可以开下的。
所以,这里需要列写两个dp,一个f[u][i],一个g[u][i],分别表示的是“u这个点出发,向祖先结点选距离≤i的全体和u的子树的全体结点方案的最小花费”,以及“u对u的子树下距离u点距离≥i的点的全体的点集的最小花费”。
那么,我们先讨论一下g[ ][ ]
- g[ ][ ]的值的求解方式:
g[u][i] += g[v][i-1],这个还是比较好理解的:
- 最关键的f[ ][ ]的求解:
因为要是u结点出发,包含距离为i的所有的点,那么我们可以直接是用(i + g[u][i + 1])来求f[u][i]。但是,有时候可以用已经取出来的f[v][i+1]来做这个,那么此时的答案就是(f[v][i + 1] - g[v][i] + g[u][i + 1]),其中,(f[v][i + 1] - g[v][i])指的是通过v来代替“+i”使得u向周围范围为i的结点都能被覆盖完。
但是,这里的f[u][i]是有初始值的,不然来来回回都是0可就没有意思咯!
初始化:
但是呢,i==0的时候会发生什么?值会偏小!——其实没有包含u这号点,也就是没有考虑u这个点了,所以,这里需要改一下:
。这样就可以了。
Input1
6
1 2
3 2
2 4
5 4
6 4
Input2
12
1 2
2 3
4 5
5 3
3 6
6 7
7 8
8 9
12 9
9 11
10 9
My Code:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 5005;
int N, cnt, head[maxN], f[maxN][maxN] = {0}, g[maxN][maxN] = {0};
struct Eddge
{
int nex, to;
Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN<<1];
inline void addEddge(int u, int v)
{
edge[cnt] = Eddge(head[u], v);
head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
void dfs(int u, int fa)
{
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == fa) continue;
dfs(v, u);
for(int j=1; j<=N; j++) g[u][j] += g[v][j-1];
}
g[u][0] = N; f[u][N] = N; //g是指">=j"部分包含需要的最小花费,f是指"≤j"部分包含需要的最小花费且对于祖先包含j距离(均对子树)
for(int j=N-1; j>=0; j--)
{
if(j == 0) f[u][0] = min(f[u][1], 1 + g[u][2]);
else f[u][j] = min(f[u][j+1], j + g[u][j + 1]);
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == fa) continue;
f[u][j] = min(f[u][j], f[v][j+1] - g[v][j] + g[u][j+1]);
}
}
g[u][0] = f[u][0];
for(int i=1; i<=N; i++) g[u][i] = min(g[u][i], g[u][i-1]);
}
inline void init()
{
cnt = 0;
for(int i=1; i<=N; i++) head[i] = -1;
}
int main()
{
scanf("%d", &N);
init();
for(int i=1, u, v; i<N; i++)
{
scanf("%d%d", &u, &v);
_add(u, v);
}
dfs(1, 0);
printf("%d\n", g[1][0]);
return 0;
}