P1219 八皇后
题目大意:
给出一个n*n的正方形棋盘,在上棋盘上放下n个皇后,要求每个皇后所在的行,列,两条对角线上没有其他皇后,输出前三种解法(按字典序排,输出结果从上到下用列号表示),并且最后输出解的个数。
输入格式:
一个数字N (6 <= n <= 13) 表示棋盘是n * n大小的。
输出格式:
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入样例1:
6
输出样例1:
2 4 6 1 3 5 3 6 2 5 1 4 4 1 5 2 6 3 4
分析:
对角线的表示方法(画个图就明白了),通过标记找符合的位置,找到一种解法后清除去除行以外的所有标记记录,行的记录不用清除是为了避免解的重复。
代码:


#includeusing namespace std; int a[100];//行 int b[100];//列 int c[100];//↙ int d[100];//↖ int total;//可行解的个数 int n; void dfs(int i){ if(i>n){//在棋盘上成功放下n个皇后 if(total<=2){//total从0开始,满2即输出前三个解 for(int k=1;k<=n;k++) cout<" "; cout<<endl; } total++;//记录解的个数 return; } else{ for(int j=1;j<=n;j++){ if((!b[j])&&(!c[i+j])&&(!d[i-j+n])){//d数组中加n是为了避免出现负数 a[i]=j;//在i行j列找到一个符合条件的位置放下一个皇后 b[j]=1;//标记列被占领 c[i+j]=1; d[i-j+n]=1; dfs(i+1); //return之后,回到之前的每一层执行下面三句,清除除行之外所有标记 b[j]=0; c[i+j]=0; d[i-j+n]=0; } } } } int main(){ cin>>n; dfs(1); cout< endl; return 0; }
在洛谷题解中看到有位大佬用了位运算+__builtin函数优化的方法,看评论区说大概是全洛谷最快了,不过我没看懂orz
P1101 单词方阵
题目大意:
给一n×n的字母方阵,内可能蕴含多个“yizhong
”单词。单词在方阵中是沿着同一方向连续摆放的。摆放可沿着 8个方向的任一方向,同一单词摆放时不再改变方向,单词与单词之间可以交叉,因此有可能共用字母。输出时,将不是单词的字母用*
代替,以突出显示单词。
输入格式:
第一行输入一个数n。(7≤n≤100)。
第二行开始输入n×n的字母矩阵。
输出格式:
突出显示单词的n×n矩阵。
输入样例1:
8
qyizhong
gydthkjy
nwidghji
orbzsfgz
hhgrhwth
zzzzzozo
iwdfrgng
yyyygggg
输出样例1:
*yizhong
gy******
n*i*****
o**z****
h***h***
z****o**
i*****n*
y******g
分析:
刚接触dfs不久看的题大多是像迷宫这样的,这题一下子没反应过来是一条路做到黑,感觉有点像嵌套的dfs,外面那个负责方向的改变,里面那个在确定方向后一直走,找到完整字符串后要注意回溯标记。个人感觉这道题还不错(大佬请忽略这句话,在本菜鸡眼里可能不存在水题。
代码:


#include#include<string.h> using namespace std; int n; char a[100][100]; char str[]={"yizhong"}; int vis[100][100]; int b[100][100]; int dx[8]={1,-1,0,0,1,1,-1,-1};//x方向 int dy[8]={0,0,1,-1,1,-1,-1,1};//y方向 void dfs(int x,int y,int gx,int gy,int d){ if(d==6&&a[x][y]=='g'){ vis[x][y]=1; for(int i=0;i ){ for(int j=0;j ){ if(vis[i][j]==1) b[i][j]++;//记录可以成功构成”yizhong“的坐标 } } vis[x][y]=0; return; } int nx=x+gx; int ny=y+gy; //选定方向后寻找下一个字母 if(nx>=0&&nx =0&&a[nx][ny]==str[d+1]){ vis[nx][ny]=1; dfs(nx,ny,gx,gy,d+1); vis[nx][ny]=0; } } int main(){ cin>>n; for(int i=0;i ) for(int j=0;j ){ cin>>a[i][j]; } memset(vis,0,sizeof(vis)); memset(b,0,sizeof(b)); for(int i=0;i ){ for(int j=0;j ){ if(a[i][j]=='y'){//遍历搜索'y' for(int k=0;k<8;k++){//八个方向”选定方向后一条路走到黑“ vis[i][j]=1;//标记 dfs(i,j,dx[k],dy[k],0); vis[i][j]=0; } } } } //输出结果 for(int h=0;h ){ for(int k=0;k ){ if(b[h][k]==0) cout<<'*'; else cout<<a[h][k]; } cout<<endl; } return 0; }
P1605 迷宫
题目大意:
给定一个n*m方格的迷宫,迷宫里有 t 处障碍,障碍处不可通过。给定起点坐标和终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案。在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。
输入格式:
第一行n、m(1≤n,m≤5)和 t,n为行,m为列,T为障碍总数。第二行起点坐标sx,sy,终点
坐标ex,ey。接下来 t 行,每行为障碍点的坐标。
输出格式:
给定起点坐标和终点坐标,问每个方格最多经过1次,从起点坐标到终点坐标的方
案总数。
输入样例1:
2 2 1
1 1 2 2
1 2
输出样例1:
1
分析:
迷宫这一类题目算是dfs和bfs中的经典题目,“加强版”也有很多,这题应该是最简单的版本的吧。
需要注意:每个方格至多经历一次,所以要对路径进行标记,避免重复走,每找出一个方案都要对走过的路径回溯时撤销标记。
代码:


#include#include<string.h> using namespace std; int n,m,t,a,b; int sx,sy,ex,ey; int dx[4]={0,1,0,-1}; int dy[4]={1,0,-1,0}; int ans=0; int Map[50][50];//标记障碍 int c[50][50];//标记走过的方格 void dfs(int x,int y){ if(x==ex&&y==ey){ ans++;//记录方案的数目 return; } for(int i=0;i<4;i++){ int nx=x+dx[i]; int ny=y+dy[i]; if(ny>0&&ny<=n&&nx>0&&nx<=m&&Map[nx][ny]==0&&c[nx][ny]==0){ c[nx][ny]=1; dfs(nx,ny); c[nx][ny]=0;//回溯清除标记 } } } int main(){ cin>>n>>m>>t; cin>>sx>>sy>>ex>>ey; memset(Map,0,sizeof(Map)); memset(c,0,sizeof(c)); c[sx][sy]=1; for(int i=1;i<=t;i++){ cin>>a>>b; Map[a][b]=1; } dfs(sx,sy); cout< endl; return 0; }