生活随笔
收集整理的這篇文章主要介紹了
bzoj 2756 [SCOI2012]奇怪的游戏 二分+网络流
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?
2756:[SCOI2012]奇怪的游戲
Time Limit:?40 Sec??Memory Limit:?128 MB
Submit:?4926??Solved:?1362
[Submit][Status][Discuss] 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?
?
?
Source
?
對棋盤進行黑白染色
設黑格個數為num1 數值和為sum1
設白格個數為num1 數值和為sum1
設最后都變為x
則
num1 * x – sum1 = num2 * x – sum2
x = (sum1 – sum2) / (num1 – num2)
當num1 ≠ num2時 可以解出 x 再用網絡流check即可
對于num1 = num2時 可以發現 對于一個合法的x k>=x都是一個合法的解
因為num1 = num2 =>?(num1 + num2) % 2 == 0 可以構造一層的滿覆蓋
所以可以二分x 然后用網絡流check
建圖:
如果點k為白
建邊(s,?k, x – v[k])
如果為黑
建邊(k, t, x – v[k])
對相鄰點u、v?(u為白)
建邊 (u,?v, inf)
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 #include<cmath>
6
7 #define inf (1LL<<50)
8 #define pa pair<int,int>
9 #define ll long long
10 #define p(x,y) (x-1)*m+y
11 using namespace std;
12 int read()
13 {
14 int x=
0,f=
1;
char ch=
getchar();
15 while(ch<
'0'||ch>
'9'){
if(ch==
'-')f=-
1;ch=
getchar();}
16 while(ch>=
'0'&&ch<=
'9'){x=x*
10+ch-
'0';ch=
getchar();}
17 return x*
f;
18 }
19
20 ll s0,s1;
21 int c0,c1;
22 int test,n,m,cnt,S,T;
23 int xx[
4]={
0,
0,
1,-
1},yy[
4]={
1,-
1,
0,
0};
24 int a[
45][
45];
25 int last[
2005],h[
2005],q[
2005],cur[
2005];
26 bool color[
45][
45];
27 struct edge{
28 int to,next;ll v;
29 }e[
20005];
30
31 void insert(
int u,
int v,ll w)
32 {
33 e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[cnt].v=
w;
34 e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;e[cnt].v=
0;
35 }
36 bool bfs()
37 {
38 int head=
0,tail=
1;
39 memset(h,-
1,
sizeof(h));
40 q[
0]=S;h[S]=
0;
41 while(head!=
tail)
42 {
43 int now=q[head];head++
;
44 for(
int i=last[now];i;i=
e[i].next)
45 if(e[i].v&&h[e[i].to]==-
1)
46 {
47 h[e[i].to]=h[now]+
1;
48 q[tail++]=
e[i].to;
49 }
50 }
51 return h[T]!=-
1;
52 }
53 ll dfs(
int x,ll f)
54 {
55 if(x==T)
return f;
56 ll w,used=
0;
57 for(
int i=cur[x];i;i=
e[i].next)
58 if(h[e[i].to]==h[x]+
1)
59 {
60 w=dfs(e[i].to,min(f-
used,e[i].v));
61 e[i].v-=w;e[i^
1].v+=
w;
62 if(e[i].v)cur[x]=
i;
63 used+=w;
if(used==f)
return f;
64 }
65 if(!used)h[x]=-
1;
66 return used;
67 }
68 ll dinic()
69 {
70 ll tmp=
0;
71 while(bfs())
72 {
73 for(
int i=S;i<=T;i++)cur[i]=
last[i];
74 tmp+=
dfs(S,inf);
75 }
76 return tmp;
77 }
78 bool check(ll x)
79 {
80 memset(last,
0,
sizeof(last));
81 cnt=
1;S=
0;T=n*m+
1;
82 ll tot=
0;
83 for(
int i=
1;i<=n;i++
)
84 for(
int j=
1;j<=m;j++
)
85 if(color[i][j])
86 {
87 insert(S,p(i,j),x-a[i][j]);tot+=x-
a[i][j];
88 for(
int k=
0;k<
4;k++
)
89 {
90 int nowx=i+xx[k],nowy=j+
yy[k];
91 if(nowx<
1||nowy<
1||nowx>n||nowy>m)
continue;
92 insert(p(i,j),p(nowx,nowy),inf);
93 }
94 }
95 else insert(p(i,j),T,x-
a[i][j]);
96 if(dinic()==tot)
return 1;
97 return 0;
98 }
99 int main()
100 {
101 test=
read();
102 while(test--
)
103 {
104 c0=c1=s0=s1=
0;
105 n=read();m=
read();
106 int mx=
0;
107 for(
int i=
1;i<=n;i++
)
108 for(
int j=
1;j<=m;j++
)
109 {
110 a[i][j]=read(),color[i][j]=(i+j)&
1;
111 mx=
max(mx,a[i][j]);
112 }
113 for(
int i=
1;i<=n;i++
)
114 for(
int j=
1;j<=m;j++
)
115 if(color[i][j])s1+=a[i][j],c1++
;
116 else s0+=a[i][j],c0++
;
117 if(c0!=
c1)
118 {
119 ll x=(s0-s1)/(c0-
c1);
120 if(x>=
mx)
121 if(check(x))
122 {
123 printf(
"%lld\n",x*c1-
s1);
124 continue;
125 }
126 puts(
"-1");
127 }
128 else
129 {
130 if(s0!=
s1)
131 {
132 puts(
"-1");
133 continue;
134 }
135 ll l=mx,r=
inf;
136 while(l<=
r)
137 {
138 ll mid=(l+r)>>
1;
139 if(check(mid))r=mid-
1;
140 else l=mid+
1;
141 }
142 printf(
"%lld\n",(ll)l*c1-
s1);
143 }
144 }
145 }
?
轉載于:https://www.cnblogs.com/fengzhiyuan/p/8682436.html
總結
以上是生活随笔為你收集整理的bzoj 2756 [SCOI2012]奇怪的游戏 二分+网络流的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。