POJ 1463 Strategic game

题目大意:

        Bob非常喜欢电脑游戏,特别是那种战略游戏,但有时他不能非常快速的找出最佳策略,因此他时常沮丧,现在他遇到了一个难题,在游戏中他要保卫一座中世纪古堡,通向古堡的道路是树形的(即一个结点可以把手与之相连的两条边),现在的问题是如何配置士兵使其可以把手通向古堡的所有道路并且士兵数量最少。

        现有多个测例(测例数无上限),每个测例中都会给出结点数量n(0 < n ≤ 1,500),结点编号为[0, n-1],接着会给出每个结点所连接的边的数量,以及与之相连的结点(由于道路是树形的,因此输入中每条边只出现一次),现对于每个测例给出最少的把守士兵数量。

题目链接

注释代码:

/*       
 * Problem ID : POJ 1463 Strategic game
 * Author     : Lirx.t.Una       
 * Language   : C++      
 * Run Time   : 641 ms       
 * Run Memory : 208 KB       
*/  

#include <string.h>
#include <stdio.h>

#define	TRUE		1
#define	FALSE		0

//最大结点数
#define	MAXNODEN		1500

#define	MIN(x,y)		( (x) < (y) ? (x) : (y) )

typedef	char	BOOL;

short	fath[MAXNODEN];//father,记录每个结点的父亲结点的编号
short	ncld[MAXNODEN];//number of children,记录每个结点子结点的数量
BOOL	vist[MAXNODEN];//每个结点的dp值是否计算过

//dp[i][0]表示结点子树i的顶点(即i结点)不放置士兵后子树i最少把守士兵数量
//dp[i][1]表示结点子树i的顶点(即i结点)放置士兵后子树i最少把守士兵数量
//显然有dp[i][0] = ∑dp[c][1],c为i的子结点
//并且dp[i][1] = 1 + ∑MIN( dp[c][0], dp[c][1] )
short	dp[MAXNODEN][2];

void
fdp( int node, int n ) {
	
	if ( !ncld[node] ) {//如果node为叶子结点
		
		//递归的终结
		dp[node][0] = 0;
		dp[node][1] = 1;
		
		return ;
	}
	
	int		c;//children,node的子结点
	int		dp0, dp1;//dp0表示node不放士兵的node子树最小士兵数
	        //dp1表示node放置士兵的最小数量
	
	//初始化
	dp0 = 0;
	dp1 = 0;
	
	for ( c = 0; c < n; c++ )
		if ( fath[c] == node ) {//首先c必须是node的子结点
			
			if ( !vist[c] ) {//并且c的dp值必须现计算过
				//如果没计算过则需要递归计算一下
				//这里采用记忆化所搜
				//dp即打表值
				
				fdp( c, n );
				vist[c] = TRUE;
			}
			
			//运用上述的公式
			dp0 += dp[c][1];
			dp1 += MIN( dp[c][0], dp[c][1] );
		}
		
		//完成最后的打表
		dp[node][0] = dp0;
		dp[node][1] = dp1 + 1;
}

int
main() {
	
	int		n;//结点数
	int		f, c;//father、children,父结点和子结点
	int		nc;//number of chidren node,结点的子结点数
	int		root;//根结点

	int		i;//计数变量
	
	while ( ~scanf("%d", &n) ) {
		
		root = -1;//初始化
		
		memset(vist, FALSE, sizeof(vist));
		
		for ( i = 1; i <= n; i++ ) {
			
			scanf("%d:(%d)", &f, &nc);
			ncld[f] = nc;
			
			if ( -1 == root )//第一个接受的父节点先暂时设置为根结点
				root = f;
			
			while ( nc-- ) {
				
				scanf("%d", &c);
				fath[c] = f;
				
				//如果发现某个输入过程中
				//当前子结点刚好和之前的root相等
				//则需将当前父结点更新为根结点
				if ( c == root )
					root = f;
			}
		}
		fath[root] = -1;//规定将根结点的父结点设为无效值
		
		fdp( root, n );
		
		printf("%d\n", MIN( dp[root][0], dp[root][1] ));
	}
	
	return 0;
}

无注释代码:

#include <string.h>
#include <stdio.h>

#define	TRUE		1
#define	FALSE		0

#define	MAXNODEN		1500

#define	MIN(x,y)		( (x) < (y) ? (x) : (y) )

typedef	char	BOOL;

short	fath[MAXNODEN];
short	ncld[MAXNODEN];
BOOL	vist[MAXNODEN];

short	dp[MAXNODEN][2];

void
fdp( int node, int n ) {
	
	if ( !ncld[node] ) {
		
		dp[node][0] = 0;
		dp[node][1] = 1;
		
		return ;
	}
	
	int		c;
	int		dp0, dp1;
	
	dp0 = 0;
	dp1 = 0;
	
	for ( c = 0; c < n; c++ )
		if ( fath[c] == node ) {
			
			if ( !vist[c] ) {
				
				fdp( c, n );
				vist[c] = TRUE;
			}
			
			dp0 += dp[c][1];
			dp1 += MIN( dp[c][0], dp[c][1] );
		}
		
		dp[node][0] = dp0;
		dp[node][1] = dp1 + 1;
}

int
main() {
	
	int		n;
	int		f, c;
	int		nc;
	int		root;

	int		i;
	
	while ( ~scanf("%d", &n) ) {
		
		root = -1;
		
		memset(vist, FALSE, sizeof(vist));
		
		for ( i = 1; i <= n; i++ ) {
			
			scanf("%d:(%d)", &f, &nc);
			ncld[f] = nc;
			
			if ( -1 == root )
				root = f;
			
			while ( nc-- ) {
				
				scanf("%d", &c);
				fath[c] = f;
				
				if ( c == root )
					root = f;
			}
		}
		fath[root] = -1;
		
		fdp( root, n );
		
		printf("%d\n", MIN( dp[root][0], dp[root][1] ));
	}
	
	return 0;
}

单词解释:

defend:vt, 防护,保卫

medieval:adj, 中世纪的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值