(学习了两天半的搜索学习,7.14号我们经历了并非搜索专题的考试)
【马的遍历】
-题目描述-
在n*m的棋盘上有一个马,马的坐标为x,y。求马跳到每一个坐标所需要的最小步数,若不能跳到该点,输出-1。
-输入格式-
一行,分别为n,m,x,y。
-输出格式-
n行,每行m个数,分别输出马到每一点的步数。
-样例数据-
input
3 3 1 1
output
0 3 2
3 -1 1
2 1 4
-分析-
这是一道很基础的题。因为它要求每一点的最小步数,所以我们用BFS(bfs能求出最优解)实现。
-代码-
#include<bits/stdc++.h>
using namespace std;
int n,m;//棋盘大小
int nx,ny;//马的坐标
int ans[555][555]={};//统计答案
int vis[555][555]={};//标记是否访问过
struct kk
{
int x;
int y;
}que[222222];//队列
int head=1,tail=0;//队首队尾指针
int fx[8]={1,1,-1,-1,2,2,-2,-2};
int fy[8]={2,-2,2,-2,1,-1,1,-1};//方向数组
void bfs()
{
for(;head<=tail;)
{
int x=que[head].x;
int y=que[head].y;//记录队首坐标
head++;//出队
for(int i=0;i<=7;i++)//枚举八个方向
if(x+fx[i]>=1&&x+fx[i]<=n&&y+fy[i]>=1&&y+fy[i]<=m)//假如没有超出边界
if(vis[x+fx[i]][y+fy[i]]==0)//并且没有访问过
{
vis[x+fx[i]][y+fy[i]]=1;//标记为访问过
que[++tail]=(kk){x+fx[i],y+fy[i]};//放入队列
ans[x+fx[i]][y+fy[i]]=ans[x][y]+1;//答案为上个状态的答案数+1
}
}
}
int main()
{
freopen("horse.in","r",stdin);
freopen("horse.out","w",stdout);
cin>>n>>m>>nx>>ny;
que[++tail]=(kk){nx,ny};//先将马的第一个位置放入队列
vis[nx][ny]=1;//标记为访问过
bfs();//宽度优先搜索
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m-1;j++)//枚举每一个点
if(vis[i][j]==1)
cout<<ans[i][j]<<' ';//如果访问过,说明走的到
else
cout<<-1<<' ';
if(vis[i][m]==1)
cout<<ans[i][m]<<endl;
else
cout<<-1<<endl;
}
fclose(stdin);
fclose(stdout);
return 0;
}
【中国象棋】
-题目描述-
(类似于8皇后问题)在n*m的棋盘上放若干个炮(可能是0个)。求方案数(注意:炮的放置方式是同行同列放置的两个炮之间不能有其他的棋子,否则就能进行攻击)点击打开链接(我们只选取其中百分之三十,及n,m<=6的数据)。
-输入格式-
一行包含两个整数n,m,之间由一个空格隔开。
-输出格式-
输出所有方案数(保证数据在int范围内)
-样例数据-
input
3 2
output
49
-分析-
只要有两个炮之间还有一个炮,就会形成攻击。所以每一行每一列我们最多只能放两个炮,这样就转换成了先确定好每一列的炮的状态。等所有行的状态都已经确定好了。再判断每一列的炮会不会互相攻击(如果该列的炮大于或等于3个,就会互相攻击),如果不会,答案数就加一。
(代码以及第三题已丢失)
【单词方阵】
-题目描述-
给一 n×n 的字母方阵,内可能蕴含多个“yizhong”单词。单词在方阵中是沿着同一方向连续摆放的。摆放可沿着 8 个方向的任一方向,同一单词摆放时不再改变方向,单词与单词之间可以交叉,因此有可能共用字母。输出时,将不是单词的字母用*代替,以突出显示单词。点击打开链接
-输入格式-
第一行输入一个数 n 。( 7<=n<=100 )。第二行开始输入n×n 的字母矩阵。
-输出格式-
n*n的矩阵。
-样例数据-
input
8
qyizhong
gydthkjy
nwidghji
orbzsfgz
hhgrhwth
zzzzzozo
iwdfrgng
yyyygggg
output
*yizhong
gy******
n*i*****
o**z****
h***h***
z****o**
i*****n*
y******g
-分析-
这是一道强模拟题。模拟8个方向。但是要注意边界。
-代码-
#include<bits/stdc++.h>
using namespace std;
int n;
char a[222][222];
char c[8]={'y','i','z','h','o','n','g'};
int ans[222][222];
int fx[9]={0,-1,1,0,0,1,1,-1,-1};
int fy[9]={0,0,0,-1,1,1,-1,1,-1};//八个方向
void check(int x,int y,int k)
{
if(k==1)
if(x<7)
return ;
if(k==2)
if(n-x+1<7)
if(k==3)
if(y<7)
return ;
if(k==4)
if(n-y+1<7)
return ;
if(k==5)
if(n-x+1<7||n-y+1<7)
return ;
if(k==6)
if(n-x+1<7||y<7)
return ;
if(k==7)
if(x<7||n-y+1<7)
return ;
if(k==8)
if(x<7||y<7)
return ;//8个方向边界
for(int i=0;i<=6;i++)
if(a[x+fx[k]*i][y+fy[k]*i]!=c[i])
return ;//假如有一个字母不符合退出
for(int i=0;i<=6;i++)
ans[x+fx[k]*i][y+fy[k]*i]=1;//标记
return ;
}
void work(int x,int y)
{
for(int i=1;i<=8;i++)
check(x,y,i);
}
int main()
{
freopen("dcfz.in","r",stdin);
freopen("dcfz.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
work(i,j);//每一个点都进行查找(可以判断这个点的字母是不是‘y’再进行查找)
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
if(ans[i][j]==1)
cout<<a[i][j];
else
cout<<'*';//没有标记‘*’突出
cout<<endl;
}
fclose(stdin);
fclose(stdout);
return 0;
}
<小结>
第二题审题错误。仔细审题很重要,理解题目意思很重要,认真检查很重要(样例出的良心也很重要)。要搞清楚到底用dfs还是bfs。这场考试,又掌握三个技巧:1)记忆化搜索;2)方向数组;3)打表。