题意
对于图G=(V,E)来说,最小点覆盖指的是从V中取尽量少的点组成一个集合,使得E中所有的边都与取出来的点相连。也就是说,设V‘是图G的一个顶点覆盖,则对于图中的任意一条边(u,v),要么u属于集合V’,要么v属于集合V‘。在V‘中除去任何元素后V’不在是顶点覆盖。
输入有多组数据,每组先输入N,表示N个结点(0~n-1),然后N行输入这个N个结点的信息,每行第一个数字表示第i个结点的编号,然后()内输入跟这个结点有边的点的个数,然后输入这些点的编号,保证u->v的边只会被输入一次,输出最小点覆盖数。
思路
d
p
[
u
]
[
0
/
1
]
dp[u][0/1]
dp[u][0/1]表示以
u
u
u为根节点的这棵子树的最优解,0表示不选
u
u
u这个结点,1表示选
u
u
u这个结点
不选这个结点,那么必然要选所有的子结点
d
p
[
u
]
[
0
]
+
=
d
p
[
v
]
[
1
]
dp[u][0]+=dp[v][1]
dp[u][0]+=dp[v][1]
选这个结点,那么子结点可以选也可以不选
d
p
[
u
]
[
1
]
+
=
m
i
n
(
d
p
[
v
]
[
0
]
,
d
p
[
v
]
[
1
]
)
dp[u][1]+=min(dp[v][0],dp[v][1])
dp[u][1]+=min(dp[v][0],dp[v][1])
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1505;
int n, dp[MAXN][2];
vector<int> G[MAXN];
void dfs(int u, int fa)
{
dp[u][1] = 1;
for (auto v : G[u])
{
if (v == fa) continue;
dfs(v, u);
dp[u][0] += dp[v][1];
dp[u][1] += min(dp[v][1], dp[v][0]);
}
}
int main()
{
while(~scanf("%d", &n))
{
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; i++) G[i].clear();
for (int i = 0; i < n; i++)
{
int u, v, k; scanf("%d:(%d)", &u, &k);
while (k--)
{
scanf("%d", &v);
G[u].emplace_back(v);
G[v].emplace_back(u);
}
}
dfs(0, -1);
printf("%d\n", min(dp[0][0], dp[0][1]));
}
return 0;
}
/*
4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)
*/