这里附上题目链接:DZY Loves Chessboard。
题目
描述
一个棋盘上有一些格子是坏的,另一些是正常的。对于每一个正常的格子,都要在上面放上棋子。 请找到一组解使没有两个相同颜色的棋子相邻(两个格子相邻为它们存在共同的边)
输入格式
第一行为两个数n,m。(1<=n,m<=100) 下面n行,每个格子上的字符为’-‘或’.’,’-‘表示坏掉的格子,’.'表示正常的格子。
输出格式
输出n行,每行m个字符。第i个字符串的第j个字符应为“W”,“B”或“ - ”。字符“W”是指在格子上放白色的棋子,“B”意味着放黑色的棋子,“ - ”表示坏掉的格子。 如果有多组答案,输出其中的一个。
~~手动分割~~
思路解析
本题有多种解法,总有一款适合你……
1.DFS(我自己就用的这种思路)
定义一个数black_white用来确定所放置棋子的颜色.black_white=1则该放白棋;black_white=0则该放黑棋。初始时我是将black_white设为1(也可以设为0)。
从第一行第一列的格子开始搜索:
- 先检查坐标是否越界,越界则停止搜索该方向。
- 若坐标合法,再检查该格是否被访问过。
若访问过,则停止搜索该方向;
若未访问过,则根据black_white的值在该格放入一个棋子。然后必须将下一次放置棋子的black_white取反(因为下一次应该放棋子的位置若与本次的格子相邻,则应该放相反颜色的棋子;若不相邻,则可以放置任意颜色的棋子)。 - 将本格标记为已访问过。
- 分别遍历上下左右四个相邻的格子。
AC代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int n,m;//棋盘有n行m列
char board[101][105],visit[100][105];//board为棋盘
int location[4][2]={{-1,0},{1,0},{0,1},{0,-1}};//4个方位
int check(int round,int colume)//检查函数
{
if(round>=0&&round<n&&colume>=0&&colume<m&&!visit[round][colume])//若坐标未越界且该格未被访问过
{
return 1;
}
return 0;//返回假值
}
int DFS(int round,int colume,int black_white)
{
int i,x,y;
if(!check(round,colume))//若坐标越界或该格已被访问过
{
return 0;//结束搜索
}
visit[round][colume]=1;//将该格标记为已访问过
if(board[round][colume]=='.')//若该格为空格则放置棋子
{
if(black_white)//black_whilte==1
{
board[round][colume]='B';
}
else//black_whilte==0
{
board[round][colume]='W';
}
}
for(i=0;i<4;i++)//沿四个方向继续搜索
{
x=round+location[i][0];
y=colume+location[i][1];
DFS(x,y,!black_white);//将black_whilte取反
}
return 0;
}
int main()
{
int i;
//输入数据
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
scanf("%s",board[i]);
}
//开始搜索
DFS(0,0,1);
//输出结果
for(i=0;i<n;i++)
{
printf("%s",board[i]);
printf("\n");
}
return 0;
}
2.打表(十分取巧的方法)
大家都见过国际象棋的棋盘吧?
黑白相间……是不是十分类似于本题所要求的黑白棋不能在上下左右四个方向上相邻呢?
显然,根据输入的n(行)、m(列)直接构造一个如图所示的棋盘(字符数组),遇到坏的格子就将其替换为 “ - ”。最后直接输出整个二维数组即可。
AC代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int n,m;
char board[105],result[100][105];//result为构造的棋盘,board为输入的棋盘的一行
int main()
{
int i,j;
scanf("%d%d",&n,&m);
//构造黑白棋盘
for(i=0;i<n;i++)
{
if(!i%2)
{
for(j=0;j<m;j+=2)
{
result[i][j]='B';
result[i][j+1]='W';
}
}
else
{
for(j=0;j<m;j+=2)
{
result[i][j]='W';
result[i][j+1]='B';
}
}
}
//输入棋盘
for(i=0;i<n;i++)
{
memset(board,0,sizeof(board));
scanf("%s",board);
for(j=0;j<m;j++)
{
if(board[j]=='-')//替换
{
result[i][j]='-';
}
}
}
//输出结果
for(i=0;i<n;i++)
{
printf("%s",result[i]);
printf("\n");
}
return 0;
}
3.BFS
广搜思路也很简单(基本上就是广搜模板):
- 每次搜索时以一个空的格子为队尾,最先将其入队(这个格子最先入队,那么它也会最先从队首出队)。为了称呼方便,可以将它命名为队长)。
为了操作方便,可以将这个空的格子统一安放黑棋(也可以是白棋); - 将队长周围四个格子中符合要求的格子逐一从队尾入队(将后入队的格子称为队长的队员);
- 在队员的格子上放上与队长相反颜色的棋子;
- 现任队长出队,队列中与其相邻的下一个格子“担任”新队长;
- 队列为空时,广搜结束。
AC代码
#include <stdio.h>
#include <stdlib.h>
struct box//box为方格
{
int x,y;//x为行坐标,y为列坐标
int b_w;//b_w==0则安插白棋,b_w==1则安插黑棋
};
int n,m;//棋盘为n行m列
char board[100][105];//board为棋盘
int location[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//4个方位
int check(int x,int y)//检查函数
{
if(x>=0&&x<n&&y>=0&&y<m&&board[x][y]=='.')//坐标合法且该格未被访问过
{
return 1;//返回真值
}
return 0;
}
int BFS(int round,int colume)//round为行坐标,colume为列坐标
{//每次都是以没插棋子的格子为中心,将周围四个格子中空余的格子入队
int i,x,y;
struct box que[10000];//构建队列
int head=0,tail=0;//定义队首、队尾
//从队尾入队
que[0].x=round;
que[0].y=colume;
que[0].b_w=1;
board[round][colume]='B';//未插棋子的格子统一安放黑棋
tail++;
while(head<tail)
{
if(board[que[head].x][que[head].y]=='.')//若该格可放置棋子
{
switch(que[head].b_w)
{
case 1:board[que[head].x][que[head].y]='B';break;
case 0:board[que[head].x][que[head].y]='W';break;
}
}
for(i=0;i<4;i++)//遍历4个方向
{
//计算新坐标
x=que[head].x+location[i][0];
y=que[head].y+location[i][1];
if(!check(x,y))//若检查不合格
{
continue;//直接进入下一次循环
}
//若检查合格则新点入队
que[tail].x=x;
que[tail].y=y;
//在队员的格子上放上与队长相反颜色的棋子
que[tail].b_w=!que[head].b_w;
switch(que[tail].b_w)
{
case 1:board[x][y]='B';break;
case 0:board[x][y]='W';break;
}
tail++;
}
head++;//将所有队员都入队的旧队长出队,队列中与其相邻的下一个格子“担任”新队长
}
return 0;
}
int main()
{
int i,j;
//输入数据
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
scanf("%s",board[i]);
}
//广度优先搜索
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
if(board[i][j]=='.')//若某格还未放棋子,则以此格为中心,开始广搜
{
BFS(i,j);
}
}
}
//输出结果
for(i=0;i<n;i++)
{
printf("%s",board[i]);
printf("\n");
}
return 0;
}