水題還要詳解???
有此疑問的請自行屏蔽此部落格,水題也是針對解題對象來區分的,對于剛剛接觸搜尋的大一新生,我認為,有些地方還是值得斟酌注意的,希望不喜勿噴。
雖然我已經大二了,但是代碼能力并不強,希望能堅持刷題,堅持寫部落格,認認真真寫解題報告,一方面是對自我的總結,另一方面是希望能在部落格上留下些什麼,簡單地說思路,貼貼代碼,對讀者也是不負責任的表現。
附上學長留下的搜尋題集,我會堅持做題,堅持發解題報告的。
專題四(簡單搜尋)
★★★★★?關于dfs,新接觸的話建議手動畫一畫遞歸樹,一層一層地去模拟,會幫助你了解,比看着代碼相面要實用的多!!!
題目大意:給一個棋盤,問能不能以馬的跳法不重複、無遺漏地将棋盤周遊一遍。如果可以的話,按照字典序輸出排列在先的一條路徑。
很裸的一道題目,但是有幾個需要注意的地方。
1、 馬的走法,如題目中給出的圖檔所示,和中國象棋中“馬走日”的方式類似,走一個2*1矩形的對角線。
2、“按照字典序輸出排列在先”是什麼意思呢?
兩種情況:
①針對字母:A1B2C3D4排列在A1C3B2D4之前
②針對數字:A1B2C3D4排列在A2B2C3D4之前
是以,在進行深搜的時候,八個位置的先後順序應該如下圖紅色數字标注那樣。否則會WA。
于是,我們給出移動的坐标變換數組,分别對應上述八個位置的移動:
一定要按照順序!否則必WA。
int dx[8]={-1,1,-2,2,-2,2,-1,1};///x為行數,縱坐标
int dy[8]={-2,-2,-1,-1,1,1,2,2};///y為列數,橫坐标
3、 dfs的四小步:目前操作、結束條件、搜尋條件、是否有回溯操作
這四小步也是我掌握dfs的關鍵。
其中,本題需要注意“回溯”的部分。
for(int i=0;i<8;i++){
int nx=x+dx[i];
int ny=y+dy[i];
///搜尋條件
if(nx>=1&&nx<=p&&ny>=1&&ny<=q&&!book[nx][ny]&&!success){
book[nx][ny]=true;
dfs(nx,ny,num+1);
///極為重要,回溯的思想,要去想搜尋失敗的時候,目前位置的通路标記要變回false
book[nx][ny]=false;
}
}
如上述代碼:
①按照0-7的順序進行移動,判斷是否達到搜尋條件(請注意,此處除了需要滿足不跳出棋盤外,還需要滿足下一個點未被通路和還沒有成功周遊整個棋盤兩個條件)。
②如果是,進入if語句,标記(nx,ny)已被通路,繼續dfs,将(nx,ny)的通路标記删除。
★★★★★?不斷dfs過程中,發現某一位置的下一步的八個位置要麼在來的路上被通路過了,要麼出界了,且此時整個棋盤還未周遊完,這說明,這條路徑是不通的,那麼在結束本次遞歸的時候,需要将原來标記的通路删除掉,以免在嘗試另外一種走法時産生錯誤,因為這個位置的通路與否直接影響了下一條路徑搜尋的結果。
4、 還有一個需要注意的小地方,小技巧,就是序号與字母的對應轉換。
輸出路徑代碼:
for(int j=0;j<p*q;j++){
printf("%c%d",path[j].y+'A'-1,path[j].x);
}
因為代碼中x代表行數1-26,y代表列數A-Z。而輸出要列在先,行在後,是以先y後x。
數字1+‘A’-1=‘A’,2+‘A’-1=B,以此類推。
同理,字母轉化成序号就是 -‘A’ 或者 -‘a’ 。
參考代碼:
#include<stdio.h>
#define maxn 27
struct path{
int x;
int y;
}path[maxn];
int num,p,q;
bool book[maxn][maxn];
bool success=false;
///注意字典序
int dx[8]={-1,1,-2,2,-2,2,-1,1};///x為行數,縱坐标
int dy[8]={-2,-2,-1,-1,1,1,2,2};///y為列數,橫坐标
void dfs(int x,int y,int num)
{
///目前節點加入路徑
path[num].x=x;
path[num].y=y;
///結束條件
if(num==p*q-1){
success=true;
return;
}
for(int i=0;i<8;i++){
int nx=x+dx[i];
int ny=y+dy[i];
///搜尋條件
if(nx>=1&&nx<=p&&ny>=1&&ny<=q&&!book[nx][ny]&&!success){
book[nx][ny]=true;
dfs(nx,ny,num+1);
///極為重要,回溯的思想,要去想搜尋失敗的時候,目前位置的通路标記要變回false
book[nx][ny]=false;
}
}
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
num=0;
success=false;
scanf("%d%d",&p,&q);
for(int t=1;t<=p;t++)
for(int k=1;k<=q;k++)
book[t][k]=false;
///以上為初始化
book[1][1]=true;
dfs(1,1,0);
printf("Scenario #%d:\n",i);
if(!success){
printf("impossible\n");
}
else{
for(int j=0;j<p*q;j++){
printf("%c%d",path[j].y+'A'-1,path[j].x);
}
printf("\n");
}
printf("\n");
}
return 0;
}