小胖守皇宫

树形dp

代码中f数组的空间是有点浪费的,f[maxn][5]即可

f[i][0]以i为根节点的子树i自己守卫自己

f[i][1]以i为根节点的子树i父亲守卫自己

f[i][2]以i为根节点的子树i儿子守卫自己

 #include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1500+5;
const ll Inf=1e18;
ll f[maxn][3][3][3];
//i被自己监视,被儿子监视,被父亲监视
//f[i][0][0][0] 以i为根的子树且i上有侍卫且i父亲上有侍卫且i子节点上有侍卫
//f[i][1][1][1] 以i为根的子树且i上没有侍卫且i父亲上没有侍卫且i子结点上没有侍卫
int n,m;
bool fa[maxn];
struct edge{
    int from,to,next;
}e[maxn*2];
int head[maxn],len,root;
void Insert(int x,int y){
    e[++len].from=x;e[len].to=y;e[len].next=head[x];head[x]=len;
}
void dfs(int u){
     ll tot=0x3f3f3f3f;
     for(int i=head[u];i;i=e[i].next){
         int v=e[i].to;
         dfs(v);
         f[u][0][1][1]+=min(f[v][1][0][1],min(f[v][1][1][0],f[v][0][1][1]));
         //u自己来守卫自己,子节点选取最优情况即可
         f[u][1][0][1]+=min(f[v][0][1][1],f[v][1][1][0]);
         //u父亲来守卫自己,子节点只能由子节点(u的孙子节点)或者自己守卫自己
         f[u][1][1][0]+=min(f[v][0][1][1],f[v][1][1][0]);
         tot=min(tot,f[v][0][1][1]-f[v][1][1][0]);
         //u子节点来守卫自己,对于子节点来说可以是自己守卫自己也可以是子节点(u的孙子节点)守卫自己,至少有一个守卫u(可能会亏损)
         //就够了,为了保证最优,选取亏损最小的
     }
     if(tot>0)f[u][1][1][0]+=tot;
     //假设v都是子节点(u的孙子节点)来守卫自己,加上最小正差值以后会有一个的决策变成自己守卫自己
}
void work(){
     scanf("%d",&n);
     for(int i=1;i<=n;++i){
         int id;scanf("%d",&id);
         ll val;scanf("%lld",&val);
         f[id][0][1][1]=val;
         int cnt;scanf("%d",&cnt);
         for(int j=1;j<=cnt;++j){
             int x;scanf("%d",&x);
             Insert(id,x);
             fa[x]=1;
         }
     }
     for(int i=1;i<=n;++i){
         if(!fa[i]){
             root=i;break;
         }
     }
     dfs(root);
     printf("%lld\n",min(f[root][0][1][1],f[root][1][1][0]));
}
int main(){
    freopen("a.in","r",stdin);
    work();
    return 0;
}
posted @   Chano_sb  阅读(73)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示