题意分析
状态设计
dp[rt][0]
d
p
[
r
t
]
[
0
]
表示本节点是服务器
dp[rt][1]
d
p
[
r
t
]
[
1
]
表示本节点不是服务器,其父亲节点时服务器
dp[rt][2]
d
p
[
r
t
]
[
2
]
表示本节点不是,其父节点也不是,而其子节点有一个是服务器
状态转移方程
dp[rt][0]=∑min(dp[v][0],dp[v][1])+1
d
p
[
r
t
]
[
0
]
=
∑
m
i
n
(
d
p
[
v
]
[
0
]
,
d
p
[
v
]
[
1
]
)
+
1
dp[rt][1]=∑dp[v][2]
d
p
[
r
t
]
[
1
]
=
∑
d
p
[
v
]
[
2
]
dp[rt][2]=min(dp[rt][1]−dp[v][2]+dp[v][0])
d
p
[
r
t
]
[
2
]
=
m
i
n
(
d
p
[
r
t
]
[
1
]
−
d
p
[
v
]
[
2
]
+
d
p
[
v
]
[
0
]
)
初始条件
dp[rt][0]=1
d
p
[
r
t
]
[
0
]
=
1
dp[rt][1]=0
d
p
[
r
t
]
[
1
]
=
0
dp[rt][2]=INF
d
p
[
r
t
]
[
2
]
=
I
N
F
代码总览
#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = a; i <= b; ++i)
using namespace std;
const int nmax = 1e6 + 10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
typedef struct {
int nxt, to;
} Edge;
Edge e[nmax << 1];
int head[nmax], tot = 0, n;
int dp[nmax][3];
void init() {
memset(head, -1, sizeof head);
tot = 0;
}
void add(int u, int v) {
e[tot].to = v;
e[tot].nxt = head[u];
head[u] = tot++;
}
void getdp(int rt , int fa) {
dp[rt][0] = 1;
dp[rt][1] = 0;
dp[rt][2] = 10100 + 1;
for (int i = head[rt]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if (v == fa) continue;
else getdp(v, rt);
dp[rt][0] += min(dp[v][0], dp[v][1]);
dp[rt][1] += dp[v][2];
}
for (int i = head[rt]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if (v == fa) continue;
else dp[rt][2] = min(dp[rt][2], dp[rt][1] - dp[v][2] + dp[v][0]);
}
}
int main() {
while (scanf("%d", &n) != EOF && n != -1) {
init();
int u , v, temp;
rep(i, 1, n - 1) {
scanf("%d %d", &u, &v);
add(u, v);
add(v, u);
}
getdp(1, -1);
printf("%d\n", min(dp[1][0], dp[1][2]));
scanf("%d", &temp); if(temp == -1) break;
}
return 0;
}