题目链接:https://vjudge.net/problem/POJ-1321
思路一:首先我们可以明确这是一个深度搜索的题目,与八皇后问题相似。我们建立一个函数DFS用来累计可行的方案数,我们走过一列我们就把它标记下来下次的时候就不可以再摆放在这一列(因为题目要求不可以将棋子摆放在同一行和同一列)然后就从下一行开始寻找可行的地方,直到我们摆放的棋子数与我们被要求摆放的棋子数相同时,我们就将方案数进行一次++,然后在进行递归下去。
#include<iostream>
#include <algorithm>
#include <string.h>
using namespace std;
int visit[20];
char mp[20][20];
int ans;//ans表示方案数
int k;//k表示棋子数目
int n;//n表示棋盘的大小
int DFS(int x,int y)
{
if(y>=k)//判断是否棋子已经用完,如果用完,记录方案数加1,然后直接返回0
{
ans++;
return 0;
}
for(int i=x;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(!visit[j]&&mp[i][j]=='#')//标记数组仅仅标记某一列上是否有棋子,因为每次递归下一列,所以每一列不会有冲突,只需判断这一列上是否有其他棋子
{
visit[j]=true;//如果该位置该列没被标记且为棋盘,那么在这里放上棋子,并标记,
DFS(i+1,y+1);//搜索下一列
visit[j]=false;//还要注意修改标记后递归回来要及时复原
}
}
}
return 0;
}
int main()
{
while(cin>>n>>k)
{
if(n==-1&&k==-1)
break;
memset(visit,false,sizeof(visit));
memset(mp,false,sizeof(mp));
for(int i=0;i<n;i++)
cin>>mp[i];
ans=0;
DFS(0,0);
cout<<ans<<endl;
}
return 0;
}
思路2:这题只需要深搜,每次从上一个放棋子地方的下一行开始寻找可以放棋子的地方,
当发现该点时,记录行数,并更新棋盘,将于此点同行同列的都更新为’.’,
如果找不到,则返回,当把所有棋子都放上去的时候,则找到一个接,计数+1,就这样进行搜索,可以保证AC
#include <iostream>
using namespace std;
struct p{
char s[10][10];//棋盘
int beforerow;//上一个棋子的行数
};
//st表示开始搜索的棋子所在的那一行,resnum表示剩余可放的棋子数
int n,resnum;//n表示当前的棋盘大小为n*n,k表示可放的总棋子数
int ans;//摆放的所有可能数
void DFS(p temp,int resnum)
{
if(resnum==0)//如果剩余棋子数量等于0,说明所有棋子都已经放好了,答案数+1返回
{
ans++;
return;
}
//否则就得从当前棋子的下一行开始搜索
//并且我们知道棋子数k大于行数n的情况显然是不存在的,有了肯定是无解情况,这里就不需要讨论这个
int i,j;
for(i=temp.beforerow+1;i<=n-resnum;i++)
{
for(j=0;j<n;j++)
{
if(temp.s[i][j]=='#')
{
p temp1;
temp1=temp;
temp1.beforerow=i;//记下改点的行数
int k;
for(k=i+1;k<n;k++)//更新棋盘
{
temp1.s[k][j]='.';
}
DFS(temp1,resnum-1);//放好一个棋子继续搜
}
}
}
}
int main()
{
while(cin>>n>>resnum)
{
if(n==-1&&resnum==-1)
break;
ans=0;
p temp;
temp.beforerow=-1;//此时还未放棋子,初始化为-1
for(int i=0;i<n;i++)
{
cin>>temp.s[i];
}
DFS(temp,resnum);
cout<<ans<<endl;
}
return 0;
}