考試(7.14)

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章