刷题记录:牛客NC51222Strategic game

传送门:牛客

题目描述:

Bob enjoys playing computer games, especially strategic games, but sometimes he cannot find the 
solution fast enough and then he is very sad. Now he has the following problem. He must defend a 
medieval city, the roads of which form a tree. He has to put the minimum number of soldiers on the 
nodes so that they can observe all the edges. Can you help him? 
Your program should find the minimum number of soldiers that Bob has to put for a given tree. 
For example for the tree: 
the solution is one soldier ( at the node 1).
输入:
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的题目

主要思路:

  1. 对于这道题,我们使用 d p [ u ] [ 0 / 1 ] dp[u][0/1] dp[u][0/1]分别表示当前的节点放置士兵 / / /不放置士兵的最少士兵数.
  2. 那么我们很容易就能想到转移方程,对于当前结点,假设我放置士兵的话,那么对于它的儿子来说它可以放士兵,也可以不放士兵,即

d p [ u ] [ 0 ] + = m i n ( d p [ v ] [ 0 ] , d p [ v ] [ 1 ] ) dp[u][0]+=min(dp[v][0],dp[v][1]) dp[u][0]+=min(dp[v][0],dp[v][1])

  1. 对于当前结点,假设我不放置士兵的话,那么对于它的儿子来说,每一个儿子都需要放置士兵,不然的话就无法管理那一条路了.即

d p [ u ] [ 1 ] + = d p [ v ] [ 0 ] dp[u][1]+=dp[v][0] dp[u][1]+=dp[v][0]

然后这道题就巧妙的解决了

下面是具体的代码部分:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <stack>
#include <deque>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
int n;int dp[maxn][4];
vector<int>edge[maxn];
void dfs(int u,int pre_u) {
	dp[u][0]=1;
	for(int i=0;i<edge[u].size();i++) {
		int v=edge[u][i];
		if(v==pre_u) continue;
		dfs(v,u);
		dp[u][0]+=min(dp[v][0],dp[v][1]);
		dp[u][1]+=dp[v][0];
	}
	return ;
}
int main() {
	while(scanf("%d",&n)!=EOF) {
		memset(dp,0,sizeof(dp));
		for(int i=0;i<=n;i++) edge[i].clear();
		int u,v,num;
		for(int i=1;i<=n;i++) {
			scanf("%d:(%d)",&u,&num);
			for(int j=1;j<=num;j++) {
				v=read();
				edge[u].push_back(v);
				edge[v].push_back(u);
			}
		}
		dfs(0,-1);
		cout<<min(dp[0][1],dp[0][0])<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值