bzoj2668 cqoi2012 交換棋子

2022-05-19 05:08:49 字數 1653 閱讀 2746

description

有乙個 \(n\) 行 \(m\) 列的黑白棋盤,你每次可以交換兩個相鄰格仔(相鄰是指有公共邊或公共頂點)中的棋子,最終達到目標狀態。要求第 \(i\) 行第 \(j\) 列的格仔只能參與 \(m_\)次交換。

input

第一行包含兩個整數 \(n,m(1\le n, m\le 20)\) 。以下 \(n\) 行為初始狀態,每行為乙個包含 \(m\) 個字元的 \(01\) 串,其中 \(0\) 表示黑色棋子, \(1\) 表示白色棋子。以下 \(n\) 行為目標狀態,格式同初始狀態。以下 \(n\) 行每行為乙個包含 \(m\) 個 \(0\) ~ \(9\) 數字的字串,表示每個格仔參與交換的次數上限。

output

輸出僅一行,為最小交換總次數。如果無解,輸出 \(-1\) 。

sample input

3 3110

000001

000110

100222

222222

sample output

solution

有趣的費用流題。

非常顯然,\(s\) 要連原圖中的黑點,新圖中的黑點要連 \(t\),關鍵是中間的邊怎麼搞。

於是考慮拆點,最開始一拆二發現好像不可做。最後發現一拆三是可行的。

把 \(x\) 拆成 \(x_1,x_2,x_3\) 。

其中對於每個 \(x\) 在原圖和新圖中的情況,分類連邊

在原圖中是白點,在新圖中是黑點

在原圖和新圖中狀態相同

還有點之間的連邊。對於連通的 \(x,y\) , \(:capacity=inf;cost = 1\)

注意判斷一下無解的情況就萬事大吉了。

#includeusing namespace std;

#define n 10001

#define inf 2000000000

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

char st[21][21], ed[21][21], use[21][21];

int n, m, ans, flow;

int s, t;

struct edge e[100001];

int head[n], tot = 1;

int q[n], dis[n], pre[n];

bool inq[n];

inline void insert(int u, int v, int c, int w)

inline void add(int u, int v, int c, int w)

inline bool spfa() }}

return dis[t] != inf;

}inline void mcf()

int main()

if (black ^ white)

while (spfa()) mcf();

cout << (flow == black ? ans : -1);

return 0;

}

BZOJ 2668 cqoi2012 交換棋子

time limit 3 sec memory limit 128 mb submit 1112 solved 409 submit status discuss 有乙個n行m列的黑白棋盤,你每次可以交換兩個相鄰格仔 相鄰是指有公共邊或公共頂點 中的棋子,最終達到目標狀態。要求第i行第j列的格仔只能...

BZOJ2668 cqoi2012 交換棋子

題解 可以戳這裡 其實自己yy一下就知道這樣建圖的正確性了。感覺太神奇,居然還能拆成3個點 orzzzzzzzzzzzzzzzzzzzzzzzzz 跪跪跪跪跪跪跪跪 1 include2 3 include4 5 include6 7 include8 9 include10 11 include1...

bzoj2668 cqoi2012 交換棋子

費用流題,構圖非常巧妙。考慮每個點的交換限制的約束,一看就知道是點容量,但是這裡不是一分為二,而是一分為三。首先我們把問題化簡,變成對於原圖上所有黑點,找到乙個新圖中的黑點,進行多次交換後到達。我們看到多次交換實際上是走了一條路徑 這裡不是最短路 對於這條路徑的起點和終點,僅進行了1次交換,而路徑上...