战略游戏(stragedi)

【问题描述】 

Bob喜欢玩电脑游戏,特别是战略游戏。但是他经常无法找到快速玩过游戏的办法。现在他有个问题。他要建立一个古城堡,城堡中的路形成一棵树。他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能了望到所有的路。注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被了望到。请你编一程序,给定一树,帮Bob计算出他需要放置最少的士兵.

【输入格式】

测试数据表示一棵树,描述如下:

第一行 N,表示树中结点的数目。

第二行至第N+1行,每行描述每个结点信息,依次为:该结点标号i,k(后面有k条边与结点I相连)。接下来k个数,分别是每条边的另一个结点标号r1,r2,...,rk。 

对于一个n(0

【输出格式】

输出文件仅包含一个数,为所求的最少的士兵数目。 

例如,对于如下图所示的树: 

         0

          |

         1

       /    \

    2       3

答案为1(只要一个士兵在结点1上)。 

【输入样例1】

4

0 1 1

1 2 2 3

2 0

3 0

【输出样例1】

1

【输入样例2】

5

3 3 1 4 2

1 1 0

2 0

0 0

4 0

【输出样例2】

2

【解析】

这道题和上一道【皇宫看守(guard)】有相似之处..但是这道题的状态定义与上一题有少许不同..

上一道题需要安全,但这一道题是需要安全 = =

这是个值得困扰的问题.. 你要边安全但是又只能搜索点0.0

那么我们就可以这样定义每一个点所代表的

比如说点i,我们就可以说点i是否有人,点i所连接的边(以i为根的树,同下)是否安全。这样来做一个状态,我们又可以像上一题那样分出4种状态。

f[i][0] 表示点i 没人 所连接的边 安全 的最小花费

f[i][1] 表示点i 没人 所连接的边 不安全 的最小花费

f[i][2] 表示点i 有人 所连接的边 安全 的最小花费

f[i][3] 表示点i 有人 所连接的边 不安全 的最小花费 #既然有人怎么会不安全呢.. 所以这种状态可以不管0.0

这个时候问题也就来了.. 没人不安全这个状态有没有用呢..

上一题是看点是否安全的,也就是说,以下这种状态是成立的(1表示有人,0表示没人):

1——0——0——1(根)

这样子四个点都是安全的。

但现在需要的是边安全,那么在同样情况下:

1——0——0——1(根)

这是不安全的,因为红色的边这一条边是不安全的,而蓝色这一个点的状态正是 没人不安全..

以上证明:没人不安全 这个状态是没有用的!

那么同样的道理,没人安全这种状态就需要孩子节点全都是有人安全的!

那这道题就轻易解决啦!

【核心代码】

void Tree_DP ( int x ){
	int i, j, k, f0, f1;
	f0 = 0; f1 = 1;
	for ( k = first[x]; k; k = a[k].next ){
		int y = a[k].y;
		Tree_DP (y);
		f0 += f[y][1];
		f1 += _min ( f[y][1], f[y][0] );
	}
	f[x][0] = f0;
	f[x][1] = f1;
}
【完整代码】

#include 
#include 
#include 
using namespace std;
struct node {
	int x, y, next;
}a[2100]; int first[2100], len, n;
void ins ( int x, int y ){
	len ++;
	a[len].x = x; a[len].y = y;
	a[len].next = first[x]; first[x] = len;
}
int f[2100][2];
int _min ( int x, int y ){ return x < y ? x : y; }
void Tree_DP ( int x ){
	int i, j, k, f0, f1;
	f0 = 0; f1 = 1;
	for ( k = first[x]; k; k = a[k].next ){
		int y = a[k].y;
		Tree_DP (y);
		f0 += f[y][1];
		f1 += _min ( f[y][1], f[y][0] );
	}
	f[x][0] = f0;
	f[x][1] = f1;
}
bool v[2100];
int main (){
	int i, j, k, x, y;
	scanf ( "%d", &n );
	len = 0; memset ( first, 0, sizeof (first) );
	memset ( v, false, sizeof (v) );
	for ( i = 1; i <= n; i ++ ){
		scanf ( "%d%d", &x, &k );
		for ( j = 1; j <= k; j ++ ){
			scanf ( "%d", &y );
			ins ( x, y );
			v[y] = true;
		}
	}
	int st;
	for ( i = 0; i < n; i ++ ){
		if ( v[i] == false ){
			st = i;
			break;
		}
	}
	Tree_DP (st);
	printf ( "%d\n", _min ( f[st][0], f[st][1] ) );
	return 0;
}



你可能感兴趣的:(Tree_Dp)