description
blinker最近喜歡上乙個奇怪的遊戲。
這個遊戲在乙個 n*m 的棋盤上玩,每個格仔有乙個數。每次 blinker 會選擇兩個相鄰的格仔,並使這兩個數都加上 1。
現在 blinker 想知道最少多少次能使棋盤上的數都變成同乙個數,如果永遠不能變成同乙個數則輸出-1。
input
輸入的第一行是乙個整數t,表示輸入資料有t輪遊戲組成。
每輪遊戲的第一行有兩個整數n和m, 分別代表棋盤的行數和列數。
接下來有n行,每行 m個數。
output
對於每個遊戲輸出最少能使遊戲結束的次數,如果永遠不能變成同乙個數則輸出-1。
sample input
2 2 2
1 2
2 3
3 3
1 2 3
2 3 4
4 3 2
sample output
2 -1
hint
【資料範圍】
對於30%的資料,保證 t<=10,1<=n,m<=8
對於100%的資料,保證 t<=10,1<=n,m<=40,所有數為正整數且小於1000000000
分析:
這道題需要分情況討論:
首先要明確,黑塊和白塊是**銷售的,所以黑塊一共增加了多少,白塊就增加了多少
n*m是偶數
那麼一定可以用骨牌(兩格)不重不漏的覆蓋所有棋盤
若x可行,那麼x+1一定可行,這符合二分的條件,所以二分+判定
n*m是奇數
這個時候就有方程:
x(達到的相等數值)
bs 黑塊上的原始數字之和 bn 黑塊數目
ws 白塊上的原始數字之和 wn 白塊數目
解出x,用網路流判斷是否可行
注意一下二分的下界是棋盤中的最大值
(棋盤中的數隻加不減)
簡單說一下建圖吧:
把棋盤黑白染色,黑色格仔作為第一部,白色格仔作為第二部
源點向一部連邊,容量是二分(計算)出的答案-z[i][j]
二部向匯點連邊,容量是二分(計算)出的答案-z[i][j]
在兩個部之間,相鄰格仔連容量為inf的邊
開ll不保證**的正確性,但是這個**上的**是對的
這裡寫**片
#include
#include
#include
#define ll long long
using namespace std;
const int n=2005;
const ll inf=0x33333333;
struct node;
node way[20001];
int tot,st[n],cur[n],deep[n],s,t;
intq[n],tou,wei,n,m,bn,wn;
ll bs,ws,z[45][45],mx;
inline void add(int u,int w,ll z)
inline int get(int
x,int
y)inline ll max(ll a,ll b)
int bfs(int
s,int t)
}while (toureturn deep[t]!=-1;
}ll dfs(int now,int t,ll limit)
}return flow;
}ll doit(ll num)
int check(ll x)
else add(get(i,j),t,x-z[i][j]);
}if (doit(x
*bn-bs)) return
1; else
return0;}
ll erfen()
return l*bn-bs;
}ll solve()
}int main()
printf("%lld",solve());
}}
bzoj2756 SCOI2012 奇怪的遊戲
description blinker最近喜歡上乙個奇怪的遊戲。這個遊戲在乙個 n m 的棋盤上玩,每個格仔有乙個數。每次 blinker 會選擇兩個相鄰 的格仔,並使這兩個數都加上 1。現在 blinker 想知道最少多少次能使棋盤上的數都變成同乙個數,如果永遠不能變成同 乙個數則輸出 1。inp...
bzoj2756 SCOI2012 奇怪的遊戲
blinker最近喜歡上乙個奇怪的遊戲。這個遊戲在乙個 n m 的棋盤上玩,每個格仔有乙個數。每次 blinker 會選擇兩個相鄰的格仔,並使這兩個數都加上 1。現在 blinker 想知道最少多少次能使棋盤上的數都變成同乙個數,如果永遠不能變成同乙個數則輸出 1。輸入的第一行是乙個整數t,表示輸入...
bzoj2756 SCOI2012 奇怪的遊戲
傳送門 思路 先黑白染色,設白格個數為cnt0,和為sum0,黑格個數為cnt1,和為sum1,假設最後所有點都變成了x 那麼如果cnt0 cnt1就是格仔數為奇數時 cnt0 x sum0 cnt1 x sum1 x sum0 sum1 cnt0 cnt1 格仔為偶數時x沒有意義 我們就要想新的方...