NOIP2013提高組day2 華容道

2021-07-10 19:28:11 字數 1614 閱讀 1990

給出一張n*m的棋盤,有一些點上有障礙物,其他點上都是棋子。給出q次詢問,每次詢問給出乙個空格,乙個目標棋子,乙個目標位置,每一步可以把乙個棋子移進空格,求把目標棋子移動到目標位置的最小步數。

n,m<=30,q<=500

第一眼看到就知道是大暴力題,發現詢問次數少的時候一次bfs就解決了,那麼詢問多起來呢?

預處理!

如何預處理?

我們先不想這個問題,想一想詢問少的時候的另一種做法,dp。

設fx1,y1,x2,y2表示空格在(x1,y1),目標棋子在(x2,y2)的最小步數,轉移顯然。

我們發現,在整個dp過程中x1,y1經常改變,x2,y2卻很少改變。

那我們可以改進一下dp,設fx,y,k(k=0..3)表示目標棋子在(x,y),空格在其上(下,左,右)的最小步數。

怎麼轉移?

發現這樣很難轉移,不如把每乙個狀態抽象成乙個點,然後向它所能轉移到的狀態連邊。邊權可以用n^2的bfs暴力搞出來。乙個狀態可以有兩種後繼。一種是把空格和目標棋子交換,邊權為1;另一種就是把空格換個位置,邊權自己暴力。

發現這樣建出來的圖和那些詢問的東西無關,就可以預處理出來了。(∩_∩)

然後,對於每次詢問,建立源點和匯點。(網路流打多了)從源點向每乙個目標棋子周圍的狀態連邊,邊權暴力^2,每乙個終止狀態向匯點連邊,邊權為0。

然後就可以跑一邊spfa 費用流來求答案了。時間飛起。

(原諒我網路流寫太多了,有些神經質)

#include

#include

#include

#define fo(i,a,b) for(int i=a;i<=b;i++)

#define n 35

#define m 4005

#define inf 0x7fffffff/3

using namespace std;

int n,m,q,x,y,s,sx,sy,tx,ty,xx,yy,ret,ans,tot,l,s,t;

int a[n][n],d[m][3],dis[m],p[m*4],v[m][m],b[m][m];

bool bz[n][n],f[m],r[4];

int g[4][2]=;

void add(int x,int y,int z)

int w(int x,int y,int z)

int bfs(int sx,int sy,int tx,int ty,int x,int y)

}return -1;

}int spfa()

f[p[i]]=0;

}if (dis[t]!=mx) return dis[t];else return -1;

}int main()

}s=0;t=4*n*m+1;

while (q)

fo(i,0,3)

fo(i,0,3)

printf("%d\n",spfa());

b[s][0]=0;fo(i,0,3) if (r[i]) r[i]=0,b[w(tx,ty,i)][0]--;

}}

為什麼變黑了?!(tat)

Noip2013提高組day2 花匠

我們把原序列大概抽象在函式圖上,就會得出這樣的結果 如下圖 顯然,圈出來的點就是我們要保留的,不可能存在刪掉一大段會存在更優的情況。做法就是每次順著找乙個最高的點,再找乙個最低的點,如果存在相同的則視為乙個點。include include include define fo i,j,k for i...

NOIP2013提高組 day2 花匠

這道題是dp,但是寫錯了,還是貪心簡單,而且快 仔細觀察可以發現兩個條件其實意思就是這一排花最後要成波浪狀 那我們o n 跑一遍就好了,就像把目前的花接到序列中去 根據序列目前的上公升下降判斷長度是否有增加 如果改變了增減性,ans 如果沒有改變,目前的這盆花肯定更優,雖然不加長度,但是要更新序列的...

NOIP2013提高組 day2 積木大賽

這道題正解是dp或是貪心,本寶用的是模擬,神奇的過了喲 先sort一下從大到小,因為我們可以看成在疊最高的那個時,順便完成了與它相鄰的一些 具體實現請手打,描述太麻煩啦 我們這樣處理就能快很多,可能是資料不是很強,其實還是蠻快的 雖然沒有o n 快 include include include i...