Luogu-P2016 战略游戏

 

题目

题目链接

 

测试得分:  100

 

 

主要算法 :  树型DP、点的最小覆盖,二分图(匈牙利算法)

 

 

题干:

   点的最小覆盖

 

 

应试策略:

  1. 定义状态dp[u][0/1]表示u这个节点不放/放士兵

  2. 根据题意,如果当前节点不放置士兵,那么它的子节点必须全部放置士兵,因为要满足士兵可以看到所有的边,所以dp[u][0]+=dp[to][1]其中to是u的子节点

  3. 如果当前节点放置士兵,它的子节点选不选已经不重要了(因为树形dp自下而上,上面的节点不需要考虑),所以dp[u][1]+=min(dp[to][0],dp[to][1])

  代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define FORa(i,s,e) for(int i=s;i<=e;i++)
#define FORs(i,s,e) for(int i=s;i>=e;i--)

using namespace std;
const int N=1500,M=1500;
int n,m,root,num_edge,head[N+1],f[N+1][2];
//f[i][0]表示的是在以i为根的子树中,不选i的最小覆盖数,f[i][1]表示的是在以i为根的子树中,选i的最小覆盖数
struct Edge{
    int next,to;
}edge[2*M+2]; 
void Add_edge(int from,int to) {edge[++num_edge]=(Edge){head[from],to},head[from]=num_edge;}
inline int min(int fa,int fb){return fa<fb?fa:fb;}
int Dp(int u,int fa)
{
    f[u][1]=1,f[u][0]=0;//初始化 
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=fa) Dp(v,u),f[u][0]+=f[v][1],f[u][1]+=min(f[v][0],f[v][1]);
        //如果u选,则答案是子树最小覆盖和的最小值    
        //如果u不选,则答案是子树选的最小覆盖和的最小值    
    }
}
int main()
{
    int from,to,fcnt;
    scanf("%d",&n);
    memset(f,127,sizeof(f));//初始化 
    FORa(i,1,n)
    {
        scanf("%d%d",&from,&fcnt);
        FORa(j,1,fcnt) scanf("%d",&to),Add_edge(from,to),Add_edge(to,from);
    }
    root=1,Dp(root,-1);
    printf("%d",min(f[root][0],f[root][1]));
    return 0;
}
/*4
0 1 1
1 2 2 3
2 0
3 0*/

总结:

  1.确定建立模型

  2.构建知识架构,模型体系

 

 

转载于:https://www.cnblogs.com/SeanOcean/p/11313963.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值