详解洛谷P2016 战略游戏/BZOJ0495. 树的最小点覆盖之战略游戏(贪心/树形DP)

Description

Bob喜欢玩电脑游戏,特别是战略游戏。但是他经常无法找到快速玩过游戏的办法。现在他有个问题。

他要建立一个古城堡,城堡中的路形成一棵树。他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能了望到所有的路。

注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被了望到。

请你编一程序,给定一树,帮Bob计算出他需要放置最少的士兵.

Format

Input

第一行 N,表示树中结点的数目。

第二行至第N+1行,每行描述每个结点信息,依次为:该结点标号i,k(后面有k条边与结点I相连)。

接下来k个数,分别是每条边的另一个结点标号r1,r2,...,rk。

对于一个n(0<n<=1500)个结点的树,结点标号在0到n-1之间,在输入数据中每条边只出现一次。

Output

输出文件仅包含一个数,为所求的最少的士兵数目。

Samples

输入数据 1

复制代码
4
0 1 1
1 2 2 3
2 0
3 0

Copy

输出数据 1

复制代码
1

Copy

Hint 答案为1(只要一个士兵在结点1上)。


思路1:树形DP

可以先看看详解洛谷P1352 没有上司的舞会(树形DP经典例题)-CSDN博客

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

根据题意,如果当前节点不放置士兵,那么它的子节点必须全部放置士兵,因为要满足士兵可以看到所有的边

dp[x][0] += dp[son][1]

其中son是u的子节点

如果当前节点放置士兵,只要将dp[x][1]加上它的子节点选不选的最小值就行了(因为树形dp自下而上,上面的节点不需要考虑)

dp[x][1]+=min(dp[son][0],dp[son][1])


代码(树形DP)

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,u,v,dp[10001][2];
vector<int> vec[100001];
void dfs(int fa,int x)
{
  dp[x][1] = 1;
  for(int i = 0;i < vec[x].size();i++)
    if(vec[x][i] != fa)
    {
      dfs(x,vec[x][i]);
	  dp[x][0] += dp[vec[x][i]][1];
	  dp[x][1] += min(dp[vec[x][i]][0],dp[vec[x][i]][1]);
    }
}
signed main()
{
  cin>>n;
  for(int i = 1;i <= n;i++)
  {
    int p;
    cin>>p>>u;
    for(int j = 1;j <= u;j++)
    {
      cin>>v;
      vec[p].push_back(v);
      vec[v].push_back(p);
    }
  }
  dfs(-1,0);
  cout<<min(dp[0][1],dp[0][0]);
  return 0;
}

思路2:贪心

可以按照反方向的深度优先遍历序列来进行贪心。每检查一个结点,如果当前点和当前点的父节点都不属于顶点覆盖集合,则将父节点加入到顶点覆盖集合,并标记当前节点和其父节点都被覆盖.

虽然说着思路很简单,但是代码细节蛮多的,可以参考一下。


代码(贪心)

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,u,v,ans,fat[100001],cnt;
struct st
{
  int zhi,id;
}dp[100001];
bool vis[100001];
vector<int> vec[100001];
void dfs(int fa,int x,int dep)
{
  dp[++cnt] = {dep,x};
  fat[x] = fa;
  for(int i = 0;i < vec[x].size();i++)
    if(vec[x][i] != fa)
      dfs(x,vec[x][i],dep + 1);
}
bool cmp(st x,st y)
{
  return x.zhi > y.zhi;
}
signed main()
{
  cin>>n;
  for(int i = 1;i <= n;i++)
  {
    int p;
    cin>>p>>u;
    for(int j = 1;j <= u;j++)
    {
      cin>>v;
      vec[p].push_back(v);
      vec[v].push_back(p);
    }
  }
  vis[1501] = 1;
  dfs(1501,0,1);
  sort(dp + 1,1 + dp + n,cmp);
  for(int i = 1;i <= n;i++)
    if(vis[dp[i].id] == 0 && vis[fat[dp[i].id]] == 0)
    {
      vis[fat[dp[i].id]] = 1;
      vis[dp[i].id] = 1;
      ans++;
    }
  cout<<ans;
  return 0;
}

结语

如果这篇博客对您有帮助的话,请点赞收藏关注支持一下呗!(o゜▽゜)o☆

相关推荐
前端不太难9 小时前
在 HarmonyOS 上,游戏状态该怎么“死而复生”
游戏·状态模式·harmonyos
ujainu18 小时前
Flutter + OpenHarmony 游戏开发进阶:用户输入响应——GestureDetector 实现点击发射
flutter·游戏·openharmony
ujainu18 小时前
Flutter + OpenHarmony 实现无限跑酷游戏开发实战—— 对象池化、性能优化与流畅控制
flutter·游戏·性能优化·openharmony·endless runner
呆呆敲代码的小Y19 小时前
【Unity工具篇】| 超实用工具LuBan,快速上手使用
游戏·unity·游戏引擎·unity插件·luban·免费游戏·游戏配置表
我的offer在哪里20 小时前
用 Unity 从 0 做一个「可以玩的」游戏,需要哪些步骤和流程
游戏·unity·游戏引擎
串流游戏联盟21 小时前
启程!手机也能邂逅暖暖万相奇观
游戏·远程工作
User_芊芊君子21 小时前
HCCL高性能通信库编程指南:构建多卡并行训练系统
人工智能·游戏·ai·agent·测评
前端不太难1 天前
HarmonyOS 游戏里,Ability 是如何被重建的
游戏·状态模式·harmonyos
灵狐数据FoxData1 天前
QQ农场今日回归,我们想“偷”回的到底是什么?
游戏·社交电子·业界资讯·娱乐·玩游戏
微祎_1 天前
Flutter for OpenHarmony:构建一个 Flutter 平衡球游戏,深入解析动画控制器、实时物理模拟与手势驱动交互
flutter·游戏·交互