Luogu P1979 華容道 bfs 最短路

2022-05-20 02:38:46 字數 3653 閱讀 4542

p1979 華容道

小b最近迷上了華容道,可是他總是要花很長的時間才能完成一次。於是,他想到用程式設計來完成華容道:給定一種局面,華容道是否根本就無法完成,如果能完成, 最少需要多少時間。

小b玩的華容道與經典的華容道遊戲略有不同,遊戲規則是這樣的:

在乙個\(n \times m\)棋盤上有\(n \times m\)個格仔,其中有且只有乙個格仔是空白的,其餘\(n \times (m-1)\)個格仔上每個格仔上有乙個棋子,每個棋子的大小都是\(1 \times 1\)的;

有些棋子是固定的,有些棋子則是可以移動的;

任何與空白的格仔相鄰(有公共的邊)的格仔上的棋子都可以移動到空白格仔上。

遊戲的目的是把某個指定位置可以活動的棋子移動到目標位置。

給定乙個棋盤,遊戲可以玩\(q\)次,當然,每次棋盤上固定的格仔是不會變的,但是棋盤上空白的格仔的初始位置、指定的可移動的棋子的初始位置和目標位置卻可能不同。第\(i\)次玩的時候,空白的格仔在第\(ex_i\)行第\(ey_i\)列,指定的可移動棋子的初始位置為第\(sx_i\)行第\(sy_i\)列,目標位置為第\(tx_i\)行第\(ty_i\)列。

假設小b每秒鐘能進行一次移動棋子的操作,而其他操作的時間都可以忽略不計。請你告訴小b每一次遊戲所需要的最少時間,或者告訴他不可能完成遊戲。

第一行有\(3\)個整數,每兩個整數之間用乙個空格隔開,依次表示\(n,m,q\);

接下來的\(n\)行描述乙個\(n \times m\)的棋盤,每行有\(m\)個整數,每兩個整數之間用乙個空格隔開,每個整數描述棋盤上乙個格仔的狀態,\(0\)表示該格仔上的棋子是固定的,\(1\)表示該格仔上的棋子可以移動或者該格仔是空白的。

接下來的\(q\)行,每行包含\(6\)個整數依次是\(ex_i,ey_i,sx_i,sy_i,tx_i,ty_i\),每兩個整數之間用乙個空格隔開,表示每次遊戲空白格仔的位置,指定棋子的初始位置和目標位置。

共\(q\)行,每行包含\(1\)個整數,表示每次遊戲所需要的最少時間,如果某次遊戲無法完成目標則輸出\(-1\)。

3 4 2

0 1 1 1

0 1 1 0

0 1 0 0

3 2 1 2 2 2

1 2 2 2 3 2

2

-1

【輸入輸出樣例說明】

棋盤上劃叉的格仔是固定的,紅色格仔是目標位置,圓圈表示棋子,其中綠色圓圈表示目標棋子。

第一次遊戲,空白格仔的初始位置是\((3,2)\)(圖中空白所示),遊戲的目標是將初始位置在\((1,2)\)上的棋子(圖中綠色圓圈所代表的棋子)移動到目標位置\((2,2)\)(圖中紅色的格仔)上。

移動過程如下:

第二次遊戲,空白格仔的初始位置是\((1,2)\)(圖中空白所示),遊戲的目標是將初始位置在\((2,2)\)上的棋子(圖中綠色圓圈所示)移動到目標位置\((3,2)\)上。

要將指定塊移入目標位置,必須先將空白塊移入目標位置,空白塊要移動到目標位置,必然是從位置\((2,2)\)上與當前圖中目標位置上的棋子交換位置,之後能與空白塊交換位置的只有當前圖中目標位置上的那個棋子,因此目標棋子永遠無法走到它的目標位置,遊戲無法完成。

【資料範圍】

對於\(30 \%\)的資料,\(1 \leq n,m \leq 10,q=1\);

對於\(60 \%\)的資料,\(1 \leq n,m \leq 30,q \leq 10\);

對於\(100 \%\)的資料,\(1 \leq n,m \leq 30,q \leq 500\)。

怨念--;

這顯然是一道爆搜題,只需要搜尋就能過了。

蒐個錘子啊,要硬搜能過這題還會成為\(noip \ 2013\)的毒瘤題?我打的暴力只有\(25\)分,然而logeadd大佬有\(80\)分。

可不可以優化一下呢?其實這道題在\(bfs\)的過程中只需要記錄空白格仔所在位置以及需要移動的那顆棋子的位置就好了,所以我們不妨把每個\((sx,sy,ex,ey)\)狀態看作乙個結點,把他向所有可以轉移到的點連邊,當\((sx,sy)\)轉移到\((tx,ty)\),\((ex,ey)\)轉移到終點周圍的某個格仔時,統計答案,那麼我們就可以用\(spfa\)來寫。

但是這樣的\(spfa\)邊權只有\(1\),不就相當於是優秀一點的\(bfs\)嗎?相當於我們沒有做到任何的優化啊(雖然我依靠這個卡到了\(80\)分)。

能不能精簡一點我們點的數量呢?

想想看,要是我們玩華容道的話,會怎麼做?首先我們要把空格子「運」到那顆棋子(叫它欽定棋子好了)旁邊,然後欽定棋子移動到空格子上,空格子再在保證欽定棋子位置不改變的情況下,移動到它的前面,繼續「運」...

誒,那有效的狀態不就是空格子在欽定棋子旁邊的狀態嗎?這樣,我們狀態記錄就可以變成\((sx,sy,k)\),\(k\)表示在欽定棋子的哪個方位。點的數量一下子就從\(n^4\)變成了\(n^2\)級別的。

具體怎麼辦呢?對於每乙個位置,我們統計空格子不經過欽定棋子到達它的另一方位的最短路徑,再建空格子與欽定棋子交換這一操作的邊,就可以跑\(n^2\)級別的\(spfa\)了。

#includeusing namespace std;

typedef pairpii;

const int maxn=5005;

int n,m,q,g[35][35],dis[35][35],d[maxn];

int cnt,top[maxn],to[maxn<<3],len[maxn<<3],nex[maxn<<3];

bool vis[maxn];

int a[4]=;

int b[4]=;

inline int read()

inline int f(int x,int y)

inline void add_edge(int x,int y,int z)

void bfs(int ex,int ey,int sx,int sy,int z)

}if(z==4) return ;

int id=f(sx,sy);

for(int i=0;i<4;i++)

if(dis[sx+a[i]][sy+b[i]]>0)

add_edge(id+z,id+i,dis[sx+a[i]][sy+b[i]]);

add_edge(id+z,f(ex,ey)+(z+2)%4,1);

}void spfa(int sx,int sy)

while(!q.empty())}}

}int main()

bfs(ex,ey,sx,sy,4);

spfa(sx,sy);

int id=f(tx,ty);

int ans=0x3f3f3f3f;

for(int i=0;i<4;i++) ans=min(ans,d[id+i]);

printf("%d\n",ans==0x3f3f3f3f?-1:ans);

}return 0;

}

洛谷 P1979 華容道

題目描述 小 b 最近迷上了華容道,可是他總是要花很長的時間才能完成一次。於是,他想到用程式設計來完成華容道 給定一種局面,華容道是否根本就無法完成,如果能完成,最少需要多少時間。小 b 玩的華容道與經典的華容道遊戲略有不同,遊戲規則是這樣的 在乙個 n m 棋盤上有 n m 個格仔,其中有且只有乙...

P1979 華容道 spfa題解

問題描述 小 b 最近迷上了華容道,可是他總是要花很長的時間才能完成一次。於是,他想到用程式設計來完成華容道 給定一種局面,華容道是否根本就無法完成,如果能完成,最少需要多少時間。小 b 玩的華容道與經典的華容道遊戲略有不同,遊戲規則是這樣的 在乙個 n m 棋盤上有 n m 個格仔,其中有且只有乙...

P1979 NOIP2013 提高組 華容道

感覺這題實在是妙哉,妙在如何去掉冗餘狀態。首先我們可以發現除了空位和特殊位其他都是本質相同的,所以容易設出狀態fi,j,x,yf fi,j,x y 表示使特殊位座標為 i,j i,j i,j 空位座標為 x,y x,y x,y 的最少時間,該dpdp dp可以使用dfs dfsdf s或bf sbf...