题目链接:P2458 [SDOI2006]保安站岗
题意:
-
给出一棵 n 个节点以 1 为根的树,点有点权 v a l x val_x valx
-
选择一些点,使得点权和最小,同时每个节点要被覆盖。
-
某节点被覆盖的充要条件是被自己覆盖或被关联的点覆盖。
题解:
PS:
-
之前的题是树上两层节点相互影响的,可以用dp[u][0/1]表示节点选或不选
-
没有上司的舞会,某个孩子节点被选,此点不能选,上一层自由选
-
这道题是三层互相影响的,例如,某个孩子节点可以不选,此点没被照到,上一层就必须选
#include<iostream>
#include<vector>
using namespace std;
typedef long long LL;
const int N=1510;
int w[N];
int dp[N][3];
vector<int>vec[N];
void dfs(int u,int pre)
{
dp[u][0]=w[u];
int cnt=0,mi=1e9;
for(int i=0;i<vec[u].size();i++)
{
int v=vec[u][i];
if(v==pre) continue;
dfs(v,u);
dp[u][0]+=min(dp[v][0],min(dp[v][1],dp[v][2]));
dp[u][1]+=min(dp[v][0],dp[v][1]);
dp[u][2]+=min(dp[v][0],dp[v][1]);
if(dp[v][0]<dp[v][1]) cnt++;
else mi=min(mi,dp[v][0]-dp[v][1]);
}
if(cnt==0) dp[u][1]+=mi;
}
int main()
{
int n; cin>>n;
for(int i=1;i<=n;i++)
{
int u,k,v; cin>>u; cin>>w[u]>>k;
for(int j=1;j<=k;j++)
{
cin>>v;
vec[u].push_back(v);
vec[v].push_back(u);
}
}
dfs(1,-1);
cout<<min(dp[1][0],dp[1][1]);
return 0;
}