蒜頭君救人 狀壓DP

2021-08-10 12:40:05 字數 3117 閱讀 7816

題目描述

蒜頭君是乙個樂於助人的好孩子,這天他所在的鄉村發生了洪水,有多名村民被困於孤島上,於是蒜頭君決定去揹他們離開困境,假設蒜頭君所在的村子是 n×

m 的網格,網格中.號代表平地,#號代表該地已被洪水淹沒,a、b……等大寫字母表示該地有村民被困,s代表蒜頭君的起點,t代表蒜頭君的終點。

蒜頭君的初始速度為 k 秒一格,他每次可以向上下左右 4 個方向中的乙個移動 1 格。在背上乙個村民後,他的速度可能會降低,也可能會加快,但他的速度不能快於 1 秒每格,那麼蒜頭君想知道,他最快需要多長時間將所有村民救出?

注意:不能在終點以外的地方放下村民;可以同時背多個村民。

輸入格式

第一行 3 個正整數 n,

m(1≤

n,m≤

10),k

,分別表示村莊長度、寬度、蒜頭君初始速度。

接下來

n 行,每行乙個長度為

m的字串,表示村莊的地形,字串意義如上所述。

接下來若干行,每行乙個大寫字母、乙個整數,表示該編號的村民會使

k 增加 / 減少多少。行數等同於地形中大寫字母的個數。大寫字母按字典序,即a、b、c的順序排列,保證前後兩行的字母是連續的,村民個數小於等於 10。

輸出格式

輸出 1 個整數,表示最小用時。

樣例輸入

4 4 2

s.##

..a#

.b##

…t a -3

b 4

樣例輸出

資料規模這麼小,不是搜尋就是狀壓。

標程給出的是三進製狀壓dp,但是這樣做使得位運算的優勢不復存在了。所以時間複雜度其實也只是理性愉悅,提取某一位常數很大。而且也增加了程式設計複雜度。

事實上二進位制狀壓dp是可以的,並不會達到o(

4cnt

cnt2

) 的複雜度,而且跑得很快。

定義狀態f[

s1][

s2][

p]表示揹著的村民狀態為s1

,已經到終點的村民為s2

,蒜頭君處在

p 位置(

p只取初始狀態下村民的位置、終點位置),那麼顯然有狀態轉移: f[

s1|(

1<

1)][

s2][

y]=m

in(d

is(x

,y)v

[s1]

+f[s

1][s

2][x

]) (

x∉s2

,x∈s

1,y∉

s2,y

∉s1)

f[s1xor

t][s

2|t]

[en]

=min

(f[s

1xor

t][s

2|t]

[en]

,f[s

1][s

2][e

n])

(t∈s

1,en

為終點)

v[s] 表示在揹著的村民狀態為

s 下的速度,di

s(x,

y)表示在原圖上x,

y 的距離。都可以預處理出來。下面的**採用的是floyd求距離,當然也可以用bfs。

上述兩式分別表示到乙個地方接村民、在終點放村民。如果不用記憶化搜尋的形式,注意迴圈順序。

那麼為什麼跑得很快呢?因為在這樣的定義下,s1

與s2 是不能有交集的,這樣顯然不可能的情況在迴圈裡判斷一下就可以了,實際上可能合法的情況只有3c

nt種。再加上x,

y 與兩個集合間的關係,迴圈執行的次數不會特別多。

**:

#include
#include

#include

using namespace std;

int n,m,k,dx[4]=,dy[4]=;

int map[105][105],pos[15],id[15][15],tot,v[15];

int f[1234][1234][15],v[1234],u,inf;

char s[15][15];

int main()}}

for(k=1;k<=tot;k++)

for(i=1;i<=tot;i++)

for(j=1;j<=tot;j++)map[i][j]=min(map[i][j],map[i][k]+map[k][j]);

//floyd預處理距離

for(i=1;i<=n;i++)

for(j=1;j<=m;j++)

u=(1

<0])-1;

v[0]=k;

for(i=1;i<=u;i++)

//預處理v

memset(f,60,sizeof(f));

for(i=1;i<=v[0];i++)f[1

<1][0][i]=map[st][pos[i]]*k;

f[0][0][v[0]+1]=map[st][pos[v[0]+1]]*k;

inf=f[0][0][0];

for(j=0;jfor(i=0;i<=u;i++)

y=v[0]+1;

if(f[i][j][y]>f[i][j][x]+v[i]*map[pos[x]][pos[y]])f[i][j][y]=f[i][j][x]+v[i]*map[pos[x]][pos[y]];

}for(x=i;x;x=x-1&i)f[i^x][j|x][v[0]+1]=min(f[i^x][j|x][v[0]+1],f[i][j][v[0]+1]);//列舉子集

}printf("%d",f[0][u][v[0]+1]);

}

蒜頭君救人

問題 蒜頭君是乙個樂於助人的好孩子,這天他所在的鄉村發生了洪水,有多名村民被困於孤島上,於是蒜頭君決定去揹他們離開困境,假設蒜頭君所在的村子是 n mn m 的網格,網格中.號代表平地,號代表該地已被洪水淹沒,a b 等大寫字母表示該地有村民被困,s代表蒜頭君的起點,t代表蒜頭君的終點。蒜頭君的初始...

noip模擬賽 蒜頭君救人

分析 之前的一道模擬賽題是dp dfs,這道題是dp bfs.我們設f stu i j 為當前狀態為stu,走到 i,j 的答案,考慮怎麼設計stu,每個人的狀態有3種 要麼在原地,要麼被揹著,要麼已經到了終點,那麼用乙個3進製數儲存就可以了.下面考慮怎麼轉移,直接遞推肯定是不對的,dfs也不行,只...

狀壓dp 玉公尺田 狀壓dp

相關 強相關 327.玉公尺田 狀壓dp 小國王 狀壓dp 是井字形,本題是十字形。思路 狀態計算 時間複雜度 n 2 n 2n o n 22n 12 2 24n 2 n 2 n o n2 12 2 n 2n 2 n o n22n 12 224 看著妥妥超時,但是裡面合法狀態很少 依舊可以過 在此,...