题目链接:
题意:
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。 ‘#’ 表示棋盘区域,‘.’表示空白区域。
DFS伪代码:
void dfs()//参数用来表示状态
{
if(到达终点状态)
{
...//根据题意添加
return;
}
if(越界或者是不合法状态)
return;
if(特殊状态)//剪枝
return ;
for(扩展方式)
{
if(扩展方式所达到状态合法)
{
修改操作;//根据题意来添加
标记;
dfs();
(还原标记);
//是否还原标记根据题意
//如果加上(还原标记)就是 回溯法
}
}
}
AC代码如下:
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
int n,k,ans;//n为棋盘长度,k为放棋子的个数,ans为满足的个数.
int map[10][10];//当map[i][j]=='#'为1,其余为0.
int vis[10];//访问过的行设为1,未访问为0.
int dfs(int x,int y)
{
if(y>=k)//当所放的棋子数>=要求放的旗子数时,ans+1.
{
ans++;
return 0;
}
for(int i=x;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(map[i][j]==1&&vis[j]==0)//标记数组仅仅标记某一列上是否有棋子,因为每次递归下一列,所以每一列不会有冲突,只需判断这一列上是否有其他棋子.
{
vis[j]=1;//如果该位置该列没被标记且为棋盘,那么在这里放上棋子,并标记.
dfs(i+1,y+1);//搜索下一列.
vis[j]=0;//还要注意修改标记后递归回来要及时复原.
}
}
}
return 0;
}
int main()
{
char ch;
while(cin>>n>>k)
{
if(n==-1&&k==-1)
{
break;
}
else
{
memset(map,0,sizeof(map));
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cin>>ch;
if(ch=='#')
{
map[i][j]=1;
}
}
}
ans=0;
dfs(0,0);
cout<<ans<<endl;
}
}
return 0;
}