https://www.luogu.org/problemnew/show/P2458
思路:
dp[x][0]表示选自己,dp[x][1] 表示选儿子,dp[x][2] 表示选父亲,dp方程:dp[x][0]+=min(dp[v][1],min(dp[v][2],dp[v][0]));dp[x][2]+=min(dp[v][0],dp[v][1]);dp[x][1]有一些特殊的地方因为自己不选儿子并不一定所有的儿子都选,所以我们要选一个最优的儿子选。可以记一个f[v][0]-f[v][1]的最小值,最后把这个加进去就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1510;
const int inf=0x3f3f3f3f;
vector<int>e[maxn];
int c[maxn];
int dp[maxn][3];
int in[maxn];
void dfs(int x,int pre)
{
dp[x][0]=c[x];
for(int i=0;i<e[x].size();i++)
{
int v=e[x][i];
if(v==pre)continue;
dfs(v,x);
}
int f=0,f1=0;
int mi=inf;
for(int i=0;i<e[x].size();i++)
{
int v=e[x][i];
f1=1;
dp[x][0]+=min(dp[v][1],min(dp[v][2],dp[v][0]));
dp[x][2]+=min(dp[v][0],dp[v][1]);
if(dp[v][0]<=dp[v][1])
{
dp[x][1]+=dp[v][0];
f=1;
}
else
{
dp[x][1]+=dp[v][1];
mi=min(mi,dp[v][0]-dp[v][1]);
}
}
if(!f)dp[x][1]+=mi;
if(!f1)dp[x][1]=inf;
}
int main()
{
int n;
scanf("%d",&n);
int x,y,k;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
scanf("%d",&c[x]);
scanf("%d",&k);
for(int j=0;j<k;j++)
{
scanf("%d",&y);
in[x]++;
in[y]++;
e[x].push_back(y);
e[y].push_back(x);
}
}
dfs(1,-1);
printf("%d\n",min(dp[1][1],dp[1][0]));
return 0;
}