类型:
暴力求解中的回溯法。
题目要求:
给你一个n,1-4,代表一个n*n的棋盘,然后输入这个棋盘,‘.’表示这个位置可以放置城堡,‘X’表示这个位置有城墙。放在在同一行或列的城堡会相互进攻,除非他们之间有城墙。
你的任务就是输入一个棋盘,输出这个棋盘上最多可以同时存在几个城堡。
解题思路:
用回溯法去枚举,vis数组中0表示可以放置城堡,1表示这个位置有城堡,2表示这个位置有城墙。然后不断回溯枚举去判断。注意,回溯进去到下一层改了vis数组后,回来的时候要改回来。
细节注意:
1、改了vis数组要改回来;
2、新放置一个城堡时,判断是否和前边的冲突。要判断那个位置的前后所有位置是否冲突。刚开始只判断了前边,以为城堡就是按顺序放的,但是别忘了。例如 0100,这种,下一次判断0,0位置,要考虑0,1位置。
AC代码:
#define Local
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <cstdio>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
using namespace std;
char chess[5][5];
int vis[5][5], _max, n; //记录城堡,0代表可以放,1代表有城堡了,2代表有城墙。
int judge(int a, int b)//参数不能是n,n为全局的。
{
int i = 0, j = 0, flag = 1;
for (i = 0; i < n; i++)
{
if (i != a)
if (1 == vis[i][b])//这一列上有别的城堡
{
flag = 0;
if (i <= a)
for (j = i+1; j <= a; j++)
{
if (2 == vis[j][b])//两个城堡之间有城墙
flag = 1;
}
else
for (j = a+1; j <= i; j++)
{
if (2 == vis[j][b])//两个城堡之间有城墙
flag = 1;
}
}
}
if (!flag)
return 0;
for (i = 0; i < n; i++)
{
if (i != b)
if (1 == vis[a][i])
{
flag = 0;
if (i <= b)
for (j = i+1; j <= b; j++)
{
if (2 == vis[a][j])
flag = 1;
}
else
for (j = b+1; j <= i; j++)
{
if (2 == vis[a][j])
flag = 1;
}
}
}
return flag;
}
void DFS (int cur)
{
int i = 0, j = 0;
if (cur > _max)
_max = cur;
for(i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
if (!vis[i][j])//这个位置可以安放城堡
{
if (judge(i, j))// 比较这个位置是否可行,可行就安上
{
vis[i][j] = 1;
DFS(cur+1);
vis[i][j] = 0;
}
}
}
}
}
int main()
{
#ifdef Local
freopen("a.in", "r", stdin);
//freopen("a.out", "w", stdout);
#endif
int i = 0, j = 0;
while (cin >> n && n)
{
_max = 0;
memset(vis, 0, sizeof(vis));
memset(chess, '\0', sizeof(chess));
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
cin >> chess[i][j];
if ('X' == chess[i][j])
vis[i][j] = 2;//2代表是城墙
}
}//输入数据
DFS(0);
cout << _max << endl;
}
}