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
2 2
1 2
2 3
3 3
1 2 3
2 3 4
4 3 2
Sample Output
2
-1
-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 }