bzoj2756: [SCOI2012]奇怪的游戏

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 

 
题解:
http://hzwer.com/5992.html
code:
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define maxn 2000
 7 #define maxm 20000
 8 #define inf (1LL<<50)
 9 using namespace std;
10 typedef long long int64;
11 char ch;
12 bool ok;
13 void read(int &x){
14     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
15     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
16     if (ok) x=-x;
17 }
18 void read(int64 &x){
19     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
20     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
21     if (ok) x=-x;
22 }
23 int T,n,m,sta[42][42];
24 int64 l,r,mid,num0,num1,sum0,sum1,val[42][42];
25 struct flow{
26     int s,t,tot,now[maxn],son[maxm],pre[maxm];
27     int64 val[maxm];
28     int dis[maxn],head,tail,list[maxn];
29     bool bo[maxn];
30     void init(){s=0,t=n*m+1,tot=1,memset(now,0,sizeof(now));}
31     void put(int a,int b,int64 c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
32     void add(int a,int b,int64 c){put(a,b,c),put(b,a,0);}
33     bool bfs(){
34         memset(bo,0,sizeof(bo));
35         head=0,tail=1,list[1]=s,dis[s]=0,bo[s]=1;
36         while (head<tail){
37             int u=list[++head];
38             for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
39                 if (val[p]&&!bo[v]) bo[v]=1,dis[v]=dis[u]+1,list[++tail]=v;
40         }
41         return bo[t];
42     }
43     int64 dfs(int u,int64 rest){
44         if (u==t) return rest;
45         int64 ans=0;
46         for (int p=now[u],v=son[p];p&&rest;p=pre[p],v=son[p])
47             if (val[p]&&dis[v]==dis[u]+1){
48                 int64 d=dfs(v,min(rest,val[p]));
49                 val[p]-=d,val[p^1]+=d,ans+=d,rest-=d;
50             }
51         if (!ans) dis[u]=-1;
52         return ans;
53     }
54     int64 dinic(){
55         int64 ans=0;
56         while (bfs()) ans+=dfs(s,inf);
57         return ans;
58     }
59 }f,tmp;
60 bool check(int64 lim){
61     f=tmp;
62     int64 tot=0;
63     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)
64         if (sta[i][j]) tot+=lim-val[i][j],f.add(f.s,(i-1)*m+j,lim-val[i][j]);
65         else f.add((i-1)*m+j,f.t,lim-val[i][j]);
66     return f.dinic()==tot;
67 }
68 const int dx[4]={1,0,-1,0};
69 const int dy[4]={0,1,0,-1};
70 int main(){
71     for (int i=1;i<=40;i++) for (int j=1;j<=40;j++) sta[i][j]=(i+j)&1;
72     for (read(T);T;T--){
73         read(n),read(m),l=num0=num1=sum0=sum1=0;
74         for (int i=1;i<=n;i++) for (int j=1;j<=m;j++){
75             read(val[i][j]),l=max(l,val[i][j]);
76             if (sta[i][j]) num0++,sum0+=val[i][j];
77             else num1++,sum1+=val[i][j];
78         }
79         f.init();
80         for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (sta[i][j])
81             for (int k=0;k<4;k++){
82                 int x=i+dx[k],y=j+dy[k];
83                 if (x<=0||x>n||y<=0||y>m) continue;
84                 f.add((i-1)*m+j,(x-1)*m+y,inf);
85             }
86         tmp=f;
87         if (num0==num1){
88             if (sum0!=sum1){puts("-1");continue;}
89             for (r=inf,mid=(l+r)>>1;l<r;mid=(l+r)>>1) if (check(mid)) r=mid; else l=mid+1;
90             printf("%lld\n",l*num0-sum0);
91         }
92         else{
93             int64 ans=(sum0-sum1)/(num0-num1);
94             if (ans>=l&&check(ans)) printf("%lld\n",ans*num0-sum0);
95             else puts("-1");
96         }
97     }
98     return 0;
99 }

 

posted @ 2016-01-18 11:43  chenyushuo  阅读(292)  评论(0编辑  收藏  举报