DFS走棋盘
八皇后
题目很狗,下面这段代码过不去,为啥呢?
``因为这句话。。。
啊啊啊啊啊啊啊啊啊啊啊啊啊~搞出来了,只是在输出时把chess[i][j]改成chess[j] [i],这不就是旋转90度的事吗?
但我还是不明白为什么这种递归做出来的都要旋转90°
这那里能只凭给的几个sample就下手给他旋转90°呢?
这哪里能想的到呢?
再去看看别人用别的方法怎么做。。。
#include <iostream>
#include <stdlib.h>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int chess[8][8]={0};
int count=0;
void print(){
printf("No. %d\n",count);
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
printf("%d ",chess[i][j]);
}
printf("\n");
}
return;
}
int safe(int row,int col){//假设选择把第row行的皇后放在col列位置,
//那么这一行不用担心,只要看看这一列上有没有之前已经放好的皇后
int i,j,k;
for(i=0;i<8;i++){
if(chess[i][col]==1)return 0;
}
for(j=row,k=col;j>=0&&k>=0;j--,k--){
if(chess[j][k]==1)return 0;
}
for(j=row,k=col;j>=0&&k<8;j--,k++){
if(chess[j][k]==1)return 0;
}
return 1;
}
void nQueen(int row){//假设前row-1行的皇后已经排列好了
if(row==8){
++count;
print();
return ;
}
// else{
for(int col=0;col<8;col++){
if(safe(row,col)){
chess[row][col]=1;
nQueen(row+1);
// 成功的给第row行皇后安排了一个位置col并且成功的把它送入了接下来一行的安排
//但要知道,针对第row行可能不止col这一个合适的位置,走完了这条路之后,
//还要看看其他7条路,即假设不走这条路,等到col+1了再走
//就像之前俺总结的,一个递归里面多条路,如果vis数组(这里是chess)
//是用来限制一条路上不能重走的,那么每走完一条路都要将vis数组重置为0
chess[row][col]=0;
}
}
// }
}
int main(int argc, char** argv) {
nQueen(0);
return 0;
}
#include <bits/stdc++.h>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
//int chess[8][8];
int arr[8];//arr[i]表示第i行防的位置中列数
int cnt=0;
void print(){
printf("No. %d\n",cnt);
for(int i=0;i<8;i++){//对于第i行
for(int j=0;j<8;j++){
// printf("%d ",chess[i][j]);
cout << ((arr[j] == i) ? 1 : 0) << " ";
}
printf("\n");
}
return;
}
int safe(int row,int col){//假设选择把第row行的皇后放在col列位置,
//那么这一行不用担心,只要看看这一列上有没有之前已经放好的皇后
int i,j,k;
for(i=0;i<row;i++){//正上方
// if(chess[i][col]==1)return 0;
if(arr[i]==arr[row])return 0;//别的行也有放在这一列的
if(abs(arr[row]-arr[i])==row-i)return 0;
}
// for(j=row,k=col;j>=0&&k>=0;j--,k--){//左上
// if(chess[j][k]==1)return 0;
// }
// for(j=row,k=col;j>=0&&k<8;j--,k++){//右上
// if(chess[j][k]==1)return 0;
// }
return 1;
}
void nQueen(int row){//假设前row-1行的皇后已经排列好了
if(row==8){
++cnt;
print();
return ;
}
// else{
for(int col=0;col<8;col++){
arr[row]=col; //假设放在col位置必须先设置 arr[row]才能判断safe噢
//而之前判断safe是通过把col参数传进safe函数的,这里可以不用col这个参数
if(safe(row,col)){
// chess[row][col]=1;
nQueen(row+1);
// chess[row][col]=0;
//反正也不会干扰在第row行别的列放皇后的情况,因为直接arr[row]覆盖掉之前情况
}
}
// }
}
int main(int argc, char** argv) {
// memset(chess,0,sizeof(chess)) ;
memset(arr,0,sizeof(arr)) ;
nQueen(0);
return 0;
}
走行数大于棋子数的棋盘
#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
int chess[10][10];
int n,k;
int ans;
int vis[10];//标记第i列是否放了棋子
void dfs(int m,int index){//八皇后问题要选的只是列,这里还需要选行
if(m==k+1){
ans++;
return;
}
for(int j=index;j<n;j++){
for(int i=0;i<n;i++){
if(!vis[i]&&chess[j][i]==1){
vis[i]=1;
dfs(m+1,j+1);//把第m枚棋子放在了第i列,接下来安排第i+1枚棋子
vis[i]=0; //考虑完了 把第m枚棋子放在了第i列的情况,接下来考虑放在i+1列
// ,放在第i列的痕迹自然是要抹去的
}
}
}
}
//模拟八皇后思想大概这样,但此题还需要考虑放在哪些行 ,而且放棋子时需要考虑
//chess[?][i]==1?,对于第m枚棋子,可以放在第几行呢
//dfs函数多加一个参数index表示从index行开始找,开始是第0行
//当然第0行可以不放,在这之下找一行 ,不用担心按这样棋子放不下,放不下时dfs
//中循环条件index>n自然结束循环,m也不会走完k而增加ans
int main(){
while(cin>>n>>k){//k<=n
if(n==-1&&k==-1)break;
ans=0;
memset(vis,0,sizeof(vis));
char ch;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>ch;
if(ch=='.')chess[i][j]=0;
else chess[i][j]=1;
}
}
dfs(1,0);//八皇后是安排那八行中每行的棋子放在第几列,这里安排k枚棋子,从第一枚开始
cout<<ans<<endl;
}
return 0;
}
马走日
1490:A Knight’s Journey
//这题面还挺讨厌的。。。
//lie用英文字母表示,行用阿拉伯数字表示,走的规则是象棋里的 马走日 ,
//目的是看能否踏遍给定尺寸棋盘每个点
//哦凑,自诩英文不错,这道题真的搞蒙我了,从题目压根没看出行列到底哪个是用英文字母表示
//大概,列是用字母表示,按照字典序就是列要优先地小
//int dx[8]={-2,-2,-1,-1,1,1,2,2};
//int dy[8]={-1,1,-2,2,-2,2,-1,1};
//最后输出坐标还是先列后行 shirt!
#include <bits/stdc++.h>
using namespace std;
//#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
int p,q;
int area;
int flag=0;
//int dx[]={}
//int dy[]={}
const int N=30;
int vis[N][N];
//int dw[8][2]={{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2}};
int dw[8][2]={{-1,-2},{1,-2},{-2,-1},{2,-1},{-2,1},{2,1},{-1,2},{1,2}};
struct kkk{
int x;
int y;
};
kkk w[N*N];
void dfs(int x,int y,int step){
if(flag==1)return; //已经成功踏遍,可能有的点还没机会也没必要遍历八方啦
w[step].x=x;
w[step].y=y;
if(step==area){
flag=1;
return;
}
for(int i=0;i<8;i++){
int cx=x+dw[i][0];
int cy=y+dw[i][1];
if((cx>=1)&&(cx<=p)&&(cy>=1)&&(cy<=q)){
if(vis[cx][cy]==0){
vis[cx][cy]=1;
dfs(cx,cy,step+1);
vis[cx][cy]=0;
}
}
}
}
int main(){
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++){
// cin>>p>>q;//表示棋盘有p行q列
scanf("%d %d",&p,&q);
memset(vis,0,sizeof(vis));
vis[1][1]=1;//从位置1,1出发嘛,从此只看八方位置
flag=0;//从1,1开始深度搜索,每个点遍历八方之后看能否踏遍所有位置
area=p*q;
dfs(1,1,1);//step代表踏过的步数啦=走动步数加上最开始的1
printf("Scenario #%d:\n",i);
if(flag==1){//要输出走过的那些点,因此还要记录走过的点坐标
for(int j=1;j<=area;j++){
printf("%c%d",w[j].y+'A'-1,w[j].x);
}
printf("\n");
}
else {
printf("impossible\n");
}
printf("\n");
}
return 0;
}
//这题面还挺讨厌的。。。
//lie用英文字母表示,行用阿拉伯数字表示,走的规则是象棋里的 马走日 ,
//目的是看能否踏遍给定尺寸棋盘每个点
//哦凑,自诩英文不错,这道题真的搞蒙我了,从题目压根没看出行列到底哪个是用英文字母表示
//大概,列是用字母表示,按照字典序就是列要优先地小
//int dx[8]={-2,-2,-1,-1,1,1,2,2};
//int dy[8]={-1,1,-2,2,-2,2,-1,1};
//最后输出坐标还是先列后行 shirt!