本题是 AcWing 285. 没有上司的舞会 的对偶题
题意:
每条边上至少选择一个节点,可以选择的最小权值。
思路:
树形dp,与没有上司的舞会具有对称性
没有上司的舞会:每条边上最多选择一个点,求最大点权值之和
战略游戏:每条边上最少选择一条点,求最小点权值之和(每个点权值都为 1)
状态表示
f[u][0]
:所有以u
为根的子树中选择,并且不选u
这个点的方案
f[u][1]
:所有以u
为根的子树中选择,并且选u
这个点的方案
属性:Min
状态计算
当前u
结点不选,子结点一定选
f [ u ] [ 0 ] = ∑ ( f [ s i , 1 ] ) f[u][0]=∑(f[si,1]) f[u][0]=∑(f[si,1])
当前u
结点选,子结点一定可选可不选
f [ u ] [ 1 ] = ∑ m i n ( f [ s i , 0 ] , f [ s i , 1 ] ) f[u][1]=∑min(f[si,0],f[si,1]) f[u][1]=∑min(f[si,0],f[si,1])
时间复杂度 :
O ( n ) O(n) O(n)
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1510;
int n;
int h[N], e[N], ne[N], idx;
int dp[N][2];
bool st[N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u)
{
dp[u][0] = 0, dp[u][1] = 1;
for(int i=h[u]; ~i; i=ne[i])
{
int j=e[i];
dfs(j);
dp[u][0] += dp[j][1];
dp[u][1] += min(dp[j][0], dp[j][1]);
}
}
int main()
{
while(~scanf("%d", &n))
{
memset(h, -1, sizeof h);
memset(st, false, sizeof st);
idx = 0;
for(int i=0; i<n; ++i)
{
int id, cnt;
scanf("%d:(%d)", &id, &cnt);
while(cnt--)
{
int ver;
scanf("%d", &ver);
add(id, ver);
st[ver] = true;
}
}
int root = 0;
while(st[root]) ++root;
dfs(root);
printf("%d\n", min(dp[root][0], dp[root][1]));
}
return 0;
}