UVa 11214 - Guarding the Chessboard

題目:在一個nxm的棋盤上放上最少的皇后,使得給定的目標點(X)全部被占或者被攻擊。

分析:圖論,搜索。利用回溯法求解,需要加入一些剪枝提高效率。

            剪枝1:用當前找到的全局最小值剪枝,如果當前使用皇后數量不小於之前的最小值則拋棄;

            剪枝2:提前一步判斷,如果當前使用皇后數量+1不小於之前的最小值,且還存在X則拋棄;

            剪枝3:每次判斷當前皇后是否能夠消除X,如果不能則無須保留現場和回溯;

說明:跑了5s多╮(╯▽╰)╭。

#include <stdio.h>
#include <stdlib.h>

char maps[9][10];
int  max = 0;
void dfs(int n, int m, int d, int v)
{
	if (max <= v) {
		return;
	}
	int count = 0;
	for (int i = 0; i < n; ++ i) {
		for (int j = 0; j < m; ++ j) {
			count += (maps[i][j] == 'X');
		}
	}
	if (count == 0) {
		max = v;
		return;
	}else { // 剪枝可以,大幅度提高效率 
		if (max == v+1) {
			return;
		}
	}
	if (d >= n) {
		return;
	}
	char save[9][9], attack = -1;  
	for (int k = 0; k < m; ++ k) { // 在行內搜索
		if (attack) { // 上次沒有有效的 queue,不用再存儲
			for (int i = 0; i < n; ++ i) {
				for (int j = 0; j < m; ++ j) {
					save[i][j] = maps[i][j];
				}
			}
		}
		attack = 0; // 統計被攻擊到的目標,并刪除目標 
		for (int i = 0; i < n; ++ i) {
			for (int j = 0; j < m; ++ j) {
				if (i == d || j == k || i-d == j-k || i-d == k-j) {
					if (maps[i][j] == 'X') {
						maps[i][j] = '.';
						attack ++;
					}
				}
			}
		}
		if (attack) { // 存在有效目標則繼續搜索,并回溯 
			dfs(n, m, d, v+1);
			for (int i = 0; i < n; ++ i) { 
				for (int j = 0; j < m; ++ j) {
					maps[i][j] = save[i][j];
				}
			}
		}
	}
	dfs(n, m, d+1, v); // 搜索下一行 
}

int main()
{
	int n, m, cases = 1;
	while (~scanf("%d",&n) && n) {
		scanf("%d",&m);
		for (int i = 0; i < n; ++ i) {
			scanf("%s",maps[i]);
		}
		max = (n<m?n:m);
		dfs(n, m, 0, 0);
		printf("Case %d: %d\n", cases ++, max);
	}
	return 0;
}
測試數據:

8 8
XXXXXXXX
XXXXXXXX
XXXXXXXX
XXXXXXXX
XXXXXXXX
XXXXXXXX
XXXXXXXX
XXXXXXXX
8 8
X.......
.X......
..X.....
...X....
....X...
.....X..
......X.
.......X
9 2
XX
XX
XX
XX
XX
XX
XX
XX
XX
2 2
XX
XX
5 3
XXX
XXX
XXX
XXX
...
9 9
.X.......
........X
.........
.........
.........
...X.....
.........
..X......
.....X...
9 9
XXXXXXXXX
XXXXXXXXX
XXXX.XXXX
XXX.X.XXX
XX.X.X.XX
XXX.X.XXX
XXXX.XXXX
XXXXXXXXX
XXXXXXXXX
9 9
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX
2 2
..
..
7 7
X......
XX.....
X.X..X.
X......
X..X...
X......
XXXXXXX
0


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值