Luogu-P2324-[SCOI2005]騎士精神
阿新 • • 發佈:2019-02-04
深搜 ret 輸入 however tput 設定 tps www. oal ,這樣的解答樹是極大的(將近於枚舉棋盤的全排列)。
【題面】
題目描述:
輸入輸出格式:
輸入格式:
第一行有一個正整數T(T<=10),表示一共有N組數據。接下來有T個5×5的矩陣,0表示白色騎士,1表示黑色騎士,*表示空位。兩組數據之間沒有空行。
輸出格式:
對於每組數據都輸出一行。如果能在15步以內(包括15步)到達目標狀態,則輸出步數,否則輸出-1。
輸入輸出樣例:
Input:
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
Output:
7
-1
說明:
【題解】:
P.S.:這題並不是此時完成的,但思路仍是可貴的,記錄下來,何樂而不為?
首先確定——DFS深搜。
然而,我們很快就發現了:DFS沒有明顯的深度!!!
這時,我們將不得不轉變思路:IDDFS叠代加深。
註:下面代碼中的DFS(sx,sy,0)
是bool
類型的。
熟練敲框架(框架!??):
for(maxstep=0;!DFS(sx,sy,0)&&maxstep<15;maxstep++);
bool DFS(int x,int y,int step) { if(is_finished()) { is_solved=1; return 1; } if(step>=maxstep)return 0; for(register int i=1;i<=8;i++) { if(x+dx[i]>5||x+dx[i]<1||y+dy[i]>5||y+dy[i]<1)continue; x+=dx[i],y+=dy[i]; swap(now[x][y],now[x-dx[i]][y-dy[i]]); if(DFS(x,y,step+1)) { swap(now[x][y],now[x-dx[i]][y-dy[i]]); return 1; } swap(now[x][y],now[x-dx[i]][y-dy[i]]); x-=dx[i],y-=dy[i]; } return 0; }
好吧也不算太難。。。
HOWEVER——
過不了。潑冷水(誰裸叠代加深過了我給他\(10^{10^{10}}\%1RMB\))
優化??
LevelUp!——\(IDA*\)
也就是\(A*\)優化的叠代加深。
簡單的來說就是:如果當前步數+理想狀態(calc估價函數)都無法在maxstep步內到達目標,即剪枝。
那麽估價函數怎麽設定?
別急,一個一個來。
在目標棋盤上,如果一個騎士不在自己的位置上(即黑白不對應),那麽這一步是一定要走的。
那麽,calc()
的設定方式是顯而易見了:
inline int calc() { register int i,j,count=0; for(i=1;i<=5;i++) for(j=1;j<=5;j++) if(now[i][j]!=goal[i][j]&&now[i][j]!=‘*‘&&goal[i][j]!=‘*‘)count++; return count; }
好了,放CODE:
#include<iostream>
using namespace std;
const int dx[9]={0,-2,-1,1,2,2,1,-1,-2};
const int dy[9]={0,1,2,2,1,-1,-2,-2,-1};
const char goal[6][6]={{0},{0,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘},{0,‘0‘,‘1‘,‘1‘,‘1‘,‘1‘},{0,‘0‘,‘0‘,‘*‘,‘1‘,‘1‘},{0,‘0‘,‘0‘,‘0‘,‘0‘,‘1‘},{0,‘0‘,‘0‘,‘0‘,‘0‘,‘0‘}};
char now[6][6];
bool is_solved;
int maxstep;
inline bool is_finished()
{
register int i,j;
for(i=1;i<=5;i++)
for(j=1;j<=5;j++)
if(goal[i][j]!=now[i][j])return 0;
return 1;
}
inline int calc()
{
register int i,j,count=0;
for(i=1;i<=5;i++)
for(j=1;j<=5;j++)
if(now[i][j]!=goal[i][j]&&now[i][j]!=‘*‘&&goal[i][j]!=‘*‘)count++;
return count;
}
bool DFS(int x,int y,int step)
{
if(is_finished())
{
is_solved=1;
return 1;
}
if(step>=maxstep||step+calc()>maxstep)return 0;
for(register int i=1;i<=8;i++)
{
if(x+dx[i]>5||x+dx[i]<1||y+dy[i]>5||y+dy[i]<1)continue;
x+=dx[i],y+=dy[i];
swap(now[x][y],now[x-dx[i]][y-dy[i]]);
if(DFS(x,y,step+1))
{
swap(now[x][y],now[x-dx[i]][y-dy[i]]);
return 1;
}
swap(now[x][y],now[x-dx[i]][y-dy[i]]);
x-=dx[i],y-=dy[i];
}
return 0;
}
signed main()
{
int T;cin>>T;
while(T--)
{
is_solved=0;
register int i,j;
int sx,sy;
for(i=1;i<=5;i++)
for(j=1;j<=5;j++)
{
cin>>now[i][j];
if(now[i][j]==‘*‘)sx=i,sy=j;
}
for(maxstep=0;!DFS(sx,sy,0)&&maxstep<15;maxstep++);
if(!is_solved)cout<<"-1"<<endl;
else cout<<maxstep<<endl;
}
return 0;
}
Luogu-P2324-[SCOI2005]騎士精神