bzoj 1001……
並不會這個trick,所以筆記要詳細一點。
前置知識 : 平面圖轉對偶圖 傳送門
聽說直接$dinic$就好了,還跑得比正解快……
首先我們按照平面圖的定義,把網格圖中所有的平面以及另加的起點和終點在新圖中標號,一共有$(n - 1) * (m - 1) * 2 + 2$個點,標完樣例之後大概是這樣子的:
然後我們接著按照定義,把有相鄰的邊的點連上雙向邊,對於那些在邊界上的邊,我們分別選擇和$st$和$ed$連邊,具體來說是這樣的:
紅色的邊和$st$連邊,藍色的邊和$ed$連邊,其他黑色的邊和它相鄰的兩個聯通塊連邊。
注意$n == 1$或者$m == 1$的時候其實是一條鏈的情況,只要把最小的邊鴿掉就好了,這時候所有的邊都是要從$st$出發連到$ed$的,但是我的寫法會掛掉,所以需要拎出來特判一下。
容易發現這樣子構圖之後從$st$到$ed$的每一條路都對應了原圖中左上角到右下角的乙個鴿,這樣子我們求乙個最小鴿就變成了乙個最短路,就能方便地跑過去了。
要注意乙個細節就是說$st$和$ed$必須放在左下角和右上角(可以對調),因為我們在原圖中是要從左上角到右下角求乙個最小鴿,要不然就不代表從左上角到右下角的乙個最小鴿了吧。
連完邊之後的效果圖大概是這個大神部落格裡面的樣子。 戳這裡
時間複雜度$o(nmlognm)$。
code:
#include #includeview code#include
#include
using
namespace
std;
typedef pair
pin;
const
int n = 2e6 + 5
;const
int m = 6e6 + 5
;int n, m, tot = 0
, head[n], dis[n];
bool
vis[n];
struct
edge e[m];
inline
void add(int
from, int to, int
val)
inline
void addedge(int x, int y, int
v) inline
void read(int &x)
priority_queue
q;inline
void dij(int
st) }}
}int
main()
for(int i = 1; i < n; i++)
for(int j = 1; j <= m; j++)
for(int i = 1; i < n; i++)
for(int j = 1; j < m; j++)
} else
for(int i = 1; i < n; i++)
for(int j = 1; j <= m; j++)
for(int i = 1; i < n; i++)
for(int j = 1; j < m; j++)
}dij(st);
printf(
"%d\n
", dis[ed]);
return0;
}
P4001 BJOI2006 狼抓兔子
不少題解都是用網路流來做最小割 網路流是什麼 但對於乙個不會網路流的蒟蒻來做這題相當困難。聽機房daolao說可以重構圖做最短路。然後就baidu將平面圖轉換成乙個對偶圖,因為網路流的最小割 對偶圖的最短路,所以只要在對偶圖上跑最短路 從左上角跑到右下角 就行了。由於堆優化的dijkstra寫炸了,...
BJOI2006 狼抓兔子
現在小朋友們最喜歡的 喜羊羊與灰太狼 話說灰太狼抓羊不到,但抓兔子還是比較在行的,而且現在的兔子還比較笨,它們只有兩個窩,現在你做為狼王,面對下面這樣乙個網格的地形 左上角點為 1,1 右下角點為 n,m 上圖中n 3,m 4 有以下三種型別的道路 1 x,y x 1,y 2 x,y x,y 1 3...
BJOI2006 狼抓兔子
求乙個網格圖的最小割。這個題一看就知道是乙個最小割模型,於是就快樂的打了dinic,也就快樂的tle了。查了查資料才知道,這個題要用到對偶圖的知識 平面圖最小割對應對偶圖最短路。所謂對偶圖,就是以原圖中的面作為點 將s,t連線以將無界區域分成兩部分 原圖中的邊在對偶圖中變為連線相鄰的面,於是,顯然對...