1. 程式人生 > >Luogu-P2324-[SCOI2005]騎士精神

Luogu-P2324-[SCOI2005]騎士精神

深搜 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]騎士精神