生活随笔
收集整理的这篇文章主要介绍了
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]奇怪的游戏 二分+网络流的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。