323. 战略游戏

题目链接

323. 战略游戏

鲍勃喜欢玩电脑游戏,特别是战略游戏,但有时他找不到解决问题的方法,这让他很伤心。

现在他有以下问题。

他必须保护一座中世纪城市,这条城市的道路构成了一棵树。

每个节点上的士兵可以观察到所有和这个点相连的边。

他必须在节点上放置最少数量的士兵,以便他们可以观察到所有的边。

你能帮助他吗?

例如,下面的树:

image

只需要放置 \(1\) 名士兵(在节点 \(1\) 处),就可观察到所有的边。

输入格式

输入包含多组测试数据,每组测试数据用以描述一棵树。

对于每组测试数据,第一行包含整数 \(N\),表示树的节点数目。

接下来 \(N\) 行,每行按如下方法描述一个节点。

节点编号:(子节点数目) 子节点 子节点 …

节点编号从 \(0\)\(N−1\),每个节点的子节点数量均不超过 \(10\),每个边在输入数据中只出现一次。

输出格式

对于每组测试数据,输出一个占据一行的结果,表示最少需要的士兵数。

数据范围

\(0<N≤1500,\)
一个测试点所有 \(N\) 相加之和不超过 \(300650\)

输入样例:

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

  • 状态表示:

    • \(f[u][0]\) 表示没有选择 \(u\) 节点这棵以 \(u\) 为根节点的子树放置士兵的最少数量
    • \(f[u][1]\) 表示选择 \(u\) 节点这棵以 \(u\) 为根节点的子树放置士兵的最少数量
  • 状态计算:

    • \(f[u][0]=\sum f[v][1]\)
    • \(f[u][1]=1+\sum min(f[v][0],f[v][1]\)

分析:如果当前节点没有选,则其子节点必须要选,否则连向子节点的这条边不合题意;如果当前节点选了,则子节点可选可不选,取较小的即可

  • 时间复杂度:\(O(n)\)

代码

// Problem: 战略游戏
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/325/
// Memory Limit: 10 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1510;
int n,f[N][2];
bool v[N];
vector<int> adj[N];
void dp(int x)
{
	f[x][0]=0,f[x][1]=1;
	for(int y:adj[x])
	{
		dp(y);
		f[x][0]+=f[y][1];
		f[x][1]+=min(f[y][0],f[y][1]);
	}
}
int main()
{
    while(~scanf("%d",&n))
    {
    	memset(v,0,sizeof v);
    	for(int i=0;i<n;i++)adj[i].clear();
    	int x,s,y;
    	for(int i=0;i<n;i++)
    	{
    		scanf("%d:(%d)",&x,&s);
	    	while(s--)
	    	{
	    		scanf("%d",&y);
	    		adj[x].pb(y);
	    		v[y]=true;
	    	}
    	}
    	int root=0;
    	while(v[root])root++;
    	dp(root);
    	printf("%d\n",min(f[root][0],f[root][1]));
    }
    return 0;
}
posted @ 2022-03-18 14:09  zyy2001  阅读(56)  评论(0编辑  收藏  举报