bzoj2756 [SCOI2012]奇怪的游戏
来源:互联网 发布:淘宝规则名词解释 编辑:程序博客网 时间:2024/06/05 07:40
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*Bn-Bs=X*Wn-Ws
解出X,用网络流判断是否可行
注意一下二分的下界是棋盘中的最大值
(棋盘中的数只加不减)
简单说一下建图吧:
把棋盘黑白染色,黑色格子作为第一部,白色格子作为第二部
源点向一部连边,容量是二分(计算)出的答案-z[i][j]
二部向汇点连边,容量是二分(计算)出的答案-z[i][j]
在两个部之间,相邻格子连容量为INF的边
tip
开ll
不保证代码的正确性,但是这个网站上的代码是对的
http://www.cnblogs.com/jianglangcaijin/p/3799797.html
这里写代码片#include<cstdio>#include<cstring>#include<iostream>#define ll long longusing namespace std;const int N=2005;const ll INF=0x33333333;struct node{ int x,y,nxt; ll v;};node way[20001];int tot,st[N],cur[N],deep[N],s,t;int q[N],tou,wei,n,m,Bn,Wn;ll Bs,Ws,z[45][45],mx;inline void add(int u,int w,ll z){ tot++; way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot; tot++; way[tot].x=w;way[tot].y=u;way[tot].v=0;way[tot].nxt=st[w];st[w]=tot;}inline int get(int x,int y){return (x-1)*n+y;}inline ll max(ll a,ll b){if (a>b) return a;else return b;}int bfs(int s,int t){ memset(deep,-1,sizeof(deep)); tou=wei=0; q[++wei]=s; deep[s]=1; for (int i=s;i<=t;i++) cur[i]=st[i]; do { int r=q[++tou]; for (int i=st[r];i!=-1;i=way[i].nxt) if (way[i].v&&deep[way[i].y]==-1) { deep[way[i].y]=deep[r]+1; q[++wei]=way[i].y; } }while (tou<wei); return deep[t]!=-1;}ll dfs(int now,int t,ll limit){ if (!limit||now==t) return limit; int i; ll flow=0,f; for (i=cur[now];i!=-1;i=way[i].nxt) { cur[now]=i; if (deep[way[i].y]==deep[now]+1&&way[i].v&&(f=dfs(way[i].y,t,min(limit,way[i].v)))) { flow+=f; limit-=f; way[i].v-=f; way[i^1].v+=f; if (!limit) break; } } return flow;}ll doit(ll num){ ll ans=0; while (bfs(s,t)) ans+=dfs(s,t,INF); return ans==num; //与目标流量一样 }int check(ll x){ memset(st,-1,sizeof(st)); tot=-1; int i,j; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { if (x<z[i][j]) return 0; if ((i+j)%2==0) //B { add(s,get(i,j),x-z[i][j]); if (i>1) add(get(i,j),get(i-1,j),INF); if (j>1) add(get(i,j),get(i,j-1),INF); if (i<n) add(get(i,j),get(i+1,j),INF); if (j<m) add(get(i,j),get(i,j+1),INF); } else add(get(i,j),t,x-z[i][j]); } if (doit(x*Bn-Bs)) return 1; else return 0;}ll erfen(){ if (Bs!=Ws) return -1; ll l=mx,r=INF; ll mid; while (l<r) { mid=(l+r)>>1; if (check(mid)) r=mid; else l=mid+1; } return l*Bn-Bs;}ll solve(){ s=0;t=n*m+1; if (n*m%2==0) return erfen(); else { ll X=(Bs-Ws)/(Bn-Wn); if (check(X)) return Bn*X-Bs; else return -1; }}int main(){ int T; scanf("%d",&T); while (T--) { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { scanf("%lld",&z[i][j]); if ((i+j)%2==0) Bs+=z[i][j],Bn++; //黑块上的数和 else Ws+=z[i][j],Wn++; mx=max(mx,z[i][j]); //二分下限,棋盘上的数只加不减 } printf("%lld",solve()); }}
- bzoj2756: [SCOI2012]奇怪的游戏
- [BZOJ2756][SCOI2012]奇怪的游戏
- BZOJ2756/SCOI2012 奇怪的游戏
- bzoj2756 [SCOI2012]奇怪的游戏
- bzoj2756 [SCOI2012]奇怪的游戏
- bzoj2756 [SCOI2012]奇怪的游戏
- 【SCOI2012】bzoj2756 奇怪的游戏
- bzoj2756 [SCOI2012]奇怪的游戏
- BZOJ2756 [SCOI2012]奇怪的游戏
- 【BZOJ2756】【SCOI2012】奇怪的游戏 最大流、
- 【二分+最大流】[SCOI2012]奇怪的游戏 BZOJ2756
- bzoj2756: [SCOI2012]奇怪的游戏 二分+最大流
- 【最大流】【二分】[Scoi2012] bzoj2756 奇怪的游戏
- 【bzoj2756】【SCOI2012】【奇怪的游戏】【最大流+二分】
- BZOJ2756 【scoi2012】奇怪的游戏(二分+网络流)
- bzoj2756[SCOI2012]奇怪的游戏 二分 分类讨论 最大流
- 【bzoj2756: [SCOI2012]奇怪的游戏】 二分+网络流判断
- SCOI2012[奇怪的游戏]
- 解读什么是ERP企业管理软件?
- ThinkPHP 框架中获取配置文件的数组
- idea如何生成实体类
- invaild use of group function问题解决
- MSSQL数据库连接相关信息的sql
- bzoj2756 [SCOI2012]奇怪的游戏
- redis配置
- leetcode--32.longest-valid-parentheses
- 曾国藩家训
- Android开发,关于ZxUtils的使用(一)
- Windows下C++实现多线程
- 2017吉林省教师招聘考试:法律法规知识点梳理
- 缝纫文件中的指针
- 18位身份证验证