(學習了兩天半的搜索學習,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)打表。