hrbust 1042 过河卒[ dfs ]

题目链接   http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1042

思路:卒子所在行枚举答案,然后dfs求解。

/*
 * hrbust1042过河卒
 * 思路:卒子所在行枚举答案,然后进行不重复深搜。
 */
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std; 

char res[10]; //记录卒子所在行的状态,用来枚举当前行。
char map[6][10]; //存放棋盘。
int sum, k, tot, pd; //每次深搜的结果,要走的步数,卒子所在行到第0行对方棋子的总数,用来判断是否可以吃掉对方全部棋子。
int dir[3][2] = 
{
	{0, 1}, {0, -1}, {-1, 0}
};

//深搜,参数:行,列,走的步数,吃掉棋子的个数。
void dfs(int x, int y, int step, int ans)
{
	int bl = 0;//判断是否搜索到对方棋子了,如果搜到了,那么bl = 1,用来当前搜索结束后更新这个棋子。
	if(map[x][y] == 'K') {
		ans++; //如果搜到了,则ans加1.

		//如果走的步数等于给出的步数,搜索结束。
		if(step == k) {
			sum = max(sum, ans); //更新sum
			if(sum == tot ) pd = 2; //如果搜到的总数等于卒子所在行到第0行对方棋子的总数,那么答案就可以确定了,没必要继续下去。
			return ;
		}

		bl = 1;
	}
	if(step == k) {
		sum = max(sum, ans);
		if(sum == tot ) pd = 2;
		return ;
	}

	if(pd == 2) return ;
	map[x][y] = 'X'; //进行不重复深搜,所以要把访问过的位置标记一下,之后在还原。
	
	//向题中所给出的3个方向进行搜索。
	for(int i = 0; i < 3; i++) {
		int a = x + dir[i][0];
		int b = y + dir[i][1];
		if(a >= 0 && a < 5 && b >= 0 && b < 9 && map[a][b] != 'X') {
			dfs(a, b, step+1, ans);
		}
	}
	
	map[x][y] = '*';
	if( bl ) map[x][y] = 'K';
}

int main()
{
	int T;
	scanf("%d", &T);
	while(T--) {
		scanf("%d", &k);
		int x = 10, y; //初始化x用来统计tot的个数。
		tot = 0;
		for(int i = 0; i < 5; i++) {
			scanf("%s", map[i]);
			for(int j = 0; j < 9; j++) {
				if(map[i][j] == 'L') {
					x = i;
					y = j;
				}
				if(map[i][j] == 'K' && x >= i) tot++;
			}
		}
		//如果k太大,就需要进行剪枝,k等于k和卒子当前位置到最后一行要走的最多的步数中较小的一个。
		k = min(((x+1)*9-1) + (8-y > y ? y : 8-y), k);

		//如果tot等于0,那么答案很明显,没必要继续下去了.
		if(tot == 0) {
			printf("0\n");
			continue;
		}
		int a = 0; //a用来记录枚举时候的对方棋子的个数。
		int tmp = tot; //记录tot的值,等会还原tot会用到。
		int tmp2 = k; //记录k的值。
		strcpy(res, map[x]); //记录卒子所在行的状态。
		int da_an = 0; //最后的答案。
		//开始枚举当前行。先向左枚举.
		for(int i = y; i >= 0; i--) {
			sum = 0;
			pd = 0;
			a = 0;
			tot = tmp;
			k = tmp2;
			//改变当前行状态,因为我们在枚举的时候已经知道了a,所以深搜的时候不能再有对方棋子出现。
			for(int j = i; j <= y; j++) {
				if(map[x][j] == 'K') {
					a++;
					map[x][j] = '*';
				}
			}
			//改变步数。
			k -= (y-i);
			if(k <= 0) break;
			//改变tot.
			tot -= a;
			dfs(x, i, 0, 0); //开始搜索。
			sum += a;
			da_an = max(da_an, sum); //更新答案。
			//还原卒子所在行状态,以便下次枚举。
			for(int j = 0; j < 9; j++) {
				map[x][j] = res[j];
			}
		}
		//向右枚举,和上面操作基本类似。
		for(int i = y; i < 9; i++) {
			sum = 0;
			pd = 0;
			a = 0;
			tot = tmp;
			k = tmp2;
			for(int j = y; j <= i; j++) {
				if(map[x][j] == 'K') {
					a++;
					map[x][j] = '*';
				}
			}
			k -= (i-y);
			if(k <= 0) break;
			tot -= a;
			dfs(x, i, 0, 0);
			sum += a;
			da_an = max(da_an, sum);
			for(int j = 0; j < 9; j++) {
				map[x][j] = res[j];
			}
		}
		printf("%d\n", da_an);
	}
	return 0;
}

  

posted @ 2012-11-07 00:22  小猴子、  阅读(405)  评论(0编辑  收藏  举报