SDOI2006 保安站岗
树形dp
大水题,直接放代码了qwq(第二位用0 1 2表示三种状态,大力dp就好了)
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<stack>
#include<bitset>
#include<cmath>
using namespace std;
const int maxn=100006;
struct hzw
{
int to,next,v;
}e[maxn];
int head[maxn],cur,val[maxn];
inline void add(int a,int b)
{
e[cur].to=b;
e[cur].next=head[a];
head[a]=cur++;
}
int n,m,dp[4][maxn];
void dfs(int u,int fa)
{
int fina=0;dp[2][u]=val[u];
for (int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if (v==fa) continue;
dfs(v,u);
fina+=min(dp[1][v],dp[2][v]);
dp[2][u]+=min(min(dp[0][v],dp[1][v]),dp[2][v]);
}
dp[0][u]=fina;dp[1][u]=0x3f3f3f3f;
for (int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if (v==fa) continue;
dp[1][u]=min(dp[1][u],fina-min(dp[1][v],dp[2][v])+dp[2][v]);
}
}
signed main()
{
memset(head,-1,sizeof(head));
memset(dp,0x3f,sizeof(dp));
cin>>n;
for (int i=1,a,b,c,d,e;i<=n;++i)
{
scanf("%d%d%d",&a,&b,&c);
val[a]=b;
// cout<<a<<" "<<b<<" "<<c<<endl;
for (int j=1;j<=c;++j)
{
scanf("%d",&e);
add(a,e);
add(e,a);
}
}
dfs(1,1);
cout<<min(dp[2][1],dp[1][1]);
}