POJ1463&BUCU5973——战略游戏(中文版Strategic game)——题解

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1463&BUCU5973——战略游戏(中文版Strategic game)——题解相关的知识,希望对你有一定的参考价值。

传送门


战略游戏

时间限制:2秒
空间限制:256M


题目描述

鲍勃喜欢完战略游戏,但他有时候找不到够快的解决方案。

限制他必须保卫一座中世纪城市,城市的道路形成一棵树。

他必须把最小数量的士兵放在节点上,这样才可以观察到所有道路。

请帮鲍勃找到放置的最小士兵数。

例如下图所示的树,解决方案是放置1个士兵(放置在节点1处)。


输入描述

输入多个测试用例。

对每个测试用例:

第一行包含节点数 n ( 0 < n ≤ 1500 ) n(0<n\\leq1500) n(0<n1500)

接下来的 n n n行,每行的描述为“节点编号:(道路数) 节点编号1 节点编号2 ⋯ \\cdots ” 或 “节点编号:(0)”

节点编号为0~n-1,每个节点连接的道路数不超过10条。每条道路在输入数据中都只出现一次


输出描述

对于每个测试用例,都单行输出放置的最小士兵数。


样例一

输入

4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)

输出

1
2

题目分析

对输入样例1的数据解释如下所示:

数据解释
4节点数为4
0:(1) 1节点0连接1条道路,道路的另一端节点为1,即0~1有一条路
1:(2) 2 3节点1连接两条路,另一端分别是2、3,即12、13分别有一条路
2:(0)节点2连接0条路
3:(0)节点3连接0条路

其对应结构如题目描述中的树。


解题思路

1. 算法设计

状态表示:

  • dp[u][0]表示不再节点u放置士兵时,以节点u为根的子树放置的最少士兵数

  • dp[u][1]表示在节点u放置士兵时,以节点u为根的子树放置的最少士兵数

状态转移方程如下:

  • 若节点u不放置士兵,则它的所有子节点v都需要放置士兵,dp[u][0] += dp[v][1]

  • 若节点u放置士兵,则它的所有子节点v既可以放置士兵,也可以不放置。取两种情况的最小值dp[u][1] += min(dp[v][0], dp[v][1])

边界条件:

dp[u][0] = 0, dp[u][1] = 1

求解目标:

min(dp[root][0], dp[root][1])

算法实现

本题为典型的树形DP问题,采用一次深度优先搜索即可实现。


AC代码

#include <iostream>
#include <vector>
#include <string.h>
using namespace std;
#define mem(a, val) memset(a, val, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
const int N = 1510;

int val[N];
int dp[N][2];
int fa[N];
vector<int> E[N];

void dfs(int u) 
    dp[u][0] = 0;
    dp[u][1] = 1;
    for (int i = 0; i < E[u].size(); i++) 
        int v = E[u][i];
        dfs(v);
        dp[u][1] += min(dp[v][1], dp[v][0]);
        dp[u][0] += dp[v][1];
    


int main() 
    int n;
    while (~scanf("%d", &n)) 
        for (int i = 0; i < n; i++)  // 编号从0开始
            E[i].clear();
        
        mem(fa, -1), mem(dp, 0); // memset
        for (int i = 0; i < n; i++) 
            int a, m;
            scanf("%d:(%d)", &a, &m);
            while (m--) 
                int b;
                scanf("%d", &b);
                E[a].push_back(b);
                fa[b] = a;
            
        
        int root = 0;
        while (fa[root] != -1)
            root = fa[root];
        dfs(root);
        printf("%d\\n", min(dp[root][1], dp[root][0]));
    
    return 0;

原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/122631253

以上是关于POJ1463&BUCU5973——战略游戏(中文版Strategic game)——题解的主要内容,如果未能解决你的问题,请参考以下文章

POJ1144&BUCU5892——电话网络(中文版)——题解(简略版)

做题记录 POJ 1463

poj 1463 Strategic game DP

[POJ 1463] Strategic Game

poj1463 Strategic game

poj1463(简单树形dp)