



本题是 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;
}

该博客介绍了一种使用树形动态规划解决图论问题的方法,具体是AcWing285题目的对偶问题。题目要求在每条边上至少选择一个节点,求解最小的点权值之和。博主通过分析没有上司的舞会问题的对称性,提出了状态转移方程,并给出了O(n)的时间复杂度的解决方案。代码示例展示了如何实现这一策略。

被折叠的 条评论
为什么被折叠?



