树形DP战略游戏
Posted Vincent_0000
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树形DP战略游戏相关的知识,希望对你有一定的参考价值。
题目来源
题目描述
鲍勃喜欢玩电脑游戏,特别是战略游戏,但有时他找不到解决问题的方法,这让他很伤心。
现在他有以下问题。
他必须保护一座中世纪城市,这条城市的道路构成了一棵树。
每个节点上的士兵可以观察到所有和这个点相连的边。
他必须在节点上放置最少数量的士兵,以便他们可以观察到所有的边。
你能帮助他吗?
例如,下面的树:
1463_1.jpg.gif
只需要放置 1 名士兵(在节点 1 处),就可观察到所有的边。
输入格式
输入包含多组测试数据,每组测试数据用以描述一棵树。
对于每组测试数据,第一行包含整数 N,表示树的节点数目。
接下来 N 行,每行按如下方法描述一个节点。
节点编号:(子节点数目) 子节点 子节点 …
节点编号从 0 到 N−1,每个节点的子节点数量均不超过 10,每个边在输入数据中只出现一次。
输出格式
对于每组测试数据,输出一个占据一行的结果,表示最少需要的士兵数。
数据范围
0<N≤1500
输入样例:
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
题目思路
- 分析题目类型
从题意上看,是基于树上进行的操作,求最小值。
那么尝试使用树形DP的思路去思考这个问题。
- DP分析
对于每一个点,我们有两种状态,选择这个点和不选择这个点,那么就有种状态机的意思,如果我们不选择这个点,那么他的儿子节点时一定要选的,因为要遍历到每一条边,如果我们选择该点,那么他的儿子节点就有选择该点和不选择该点的两种选择,取最小值即可。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define For(i, a, b) for (int i = (a); i >= (b); --i)
#define debug(a) cout << #a << " = " << a << ENDL
#define ENDL "\\n"
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int N = 1500 + 5, M = N * 2, INF = 0x3f3f3f3f;
int h[N], ne[M], e[M], idx, f[N][2];
bool vis[N];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u) {
f[u][1] = 1, f[u][0] = 0;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
dfs(j);
f[u][0] += f[j][1];
f[u][1] += min(f[j][1], f[j][0]);
}
}
int main() {
#ifdef LOCAL
freopen("data.in", "r", stdin);
#endif
// ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n;
while (cin >> n) {
idx = 0;
memset(h, -1, sizeof h);
memset(vis, 0, sizeof vis);
while (n--) {
int a, b, m;
scanf("%d:(%d)", &a, &m);
while (m--) {
cin >> b;
add(a, b);
vis[b] = true;
}
}
int rt = 0;
while (vis[rt]) rt++;
dfs(rt);
cout << min(f[rt][1], f[rt][0]) << ENDL;
}
return 0;
}
反思
我考虑它为树形DP,但是没想到它还结合了状态机,以后做题目要多方向尝试!
以上是关于树形DP战略游戏的主要内容,如果未能解决你的问题,请参考以下文章