BZOJ 2756: [SCOI2012]奇怪的游戏 [最大流 二分]
2756: [SCOI2012]奇怪的游戏
Time Limit: 40 Sec Memory Limit: 128 MB
Submit: 3352 Solved: 919
[Submit][Status][Discuss]
Description
Blinker最近喜欢上一个奇怪的游戏。
这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数。每次 Blinker 会选择两个相邻
的格子,并使这两个数都加上 1。
现在 Blinker 想知道最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同
一个数则输出-1。
Input
输入的第一行是一个整数T,表示输入数据有T轮游戏组成。
每轮游戏的第一行有两个整数N和M, 分别代表棋盘的行数和列数。
接下来有N行,每行 M个数。
Output
对于每个游戏输出最少能使游戏结束的次数,如果永远不能变成同一个数则输出-1。
Sample Input
2 2
1 2
2 3
3 3
1 2 3
2 3 4
4 3 2
Sample Output
-1
HINT
【数据范围】
对于30%的数据,保证 T<=10,1<=N,M<=8
对于100%的数据,保证 T<=10,1<=N,M<=40,所有数为正整数且小于1000000000
典型的棋盘
黑白染色,黑色格子cb个,数字和为sb;白色格子cw个,数字和为sw
设最后数字为x,操作t次,每次操作一定一个黑格一个白格
cb*x=sb+t
cw*x=sw+t
解得 x=(sb-sw)/(cb-cw)
分类讨论:
1.cb!=cw 得到了x,判断合法(x>=mx)就行了
2.cb==cw (这个时候一定是n,m都是偶数)(只要有一个偶数就可以了,感谢mywaythere指出),x不确定
(1) sb!=sw 无解
(2) sb==sw 二分x是多少,找最小的合法的x
如何判断一个x合法:
黑白染色后是二分图
s--与x差值-->黑格--INF-->白格--与x差值-->t
注意:
别把m打成n别把m打成n别把m打成n别把m打成n别把m打成n别把m打成n别把m打成n别把m打成n
有好多地方啊啊啊啊啊啊啊啊啊啊啊
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=;
typedef long long ll;
const ll INF=1LL<<;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-; c=getchar();}
while(c>=''&&c<=''){x=x*+c-''; c=getchar();}
return x*f;
}
int n,m,g[][],s,t;
ll cb,cw,sb,sw,x,mx;
struct edge{
int v,ne;
ll c,f;
}e[*N<<];
int cnt,h[N];
inline void ins(int u,int v,ll c){
cnt++;
e[cnt].v=v;e[cnt].c=c;e[cnt].f=;e[cnt].ne=h[u];h[u]=cnt;
cnt++;
e[cnt].v=u;e[cnt].c=;e[cnt].f=;e[cnt].ne=h[v];h[v]=cnt;
}
int q[N],head,tail,vis[N],d[N];
bool bfs(){
memset(vis,,sizeof(vis));
memset(d,,sizeof(d));
head=tail=;
q[tail++]=s;d[s]=;vis[s]=;
while(head!=tail){
int u=q[head++];
for(int i=h[u];i;i=e[i].ne){
int v=e[i].v;
if(!vis[v]&&e[i].c>e[i].f){
vis[v]=;
d[v]=d[u]+;
if(v==t) return true;
q[tail++]=v;
}
}
}
return false;
} int cur[N];
ll dfs(int u,ll a){
if(u==t||a==) return a;
ll flow=,f;
for(int &i=cur[u];i;i=e[i].ne){
int v=e[i].v;
if(d[v]==d[u]+&&(f=dfs(v,min(a,e[i].c-e[i].f)))>){
flow+=f;
e[i].f+=f;
e[((i-)^)+].f-=f;
a-=f;
if(a==) break;
}
}
return flow;
}
ll dinic(){
ll flow=;
while(bfs()){
for(int i=s;i<=t;i++) cur[i]=h[i];
flow+=dfs(s,INF);
}
return flow;
} inline int id(int i,int j){return (i-)*m+j;}
void build(ll x){
cnt=;memset(h,,sizeof(h));
for(int i=;i<=n;i++)
for(int j=;j<=m;j++){
if((i+j)&){
ins(s,id(i,j),x-g[i][j]);
if(i->=) ins(id(i,j),id(i-,j),INF);
if(i+<=n) ins(id(i,j),id(i+,j),INF);
if(j->=) ins(id(i,j),id(i,j-),INF);
if(j+<=m) ins(id(i,j),id(i,j+),INF);
}else ins(id(i,j),t,x-g[i][j]);
}
}
bool check(ll x){
s=;t=n*m+;
build(x);
ll flow=dinic();
if(flow==x*cb-sb) return true;
else return false;
}
void solve(){
if(cb!=cw){
x=(sb-sw)/(cb-cw);
if(x>=mx&&check(x)) printf("%lld\n",cb*x-sb);
else puts("-1");
}else{
if(sb!=sw) puts("-1");
else{
ll l=mx,r=INF;
while(l<=r){
ll mid=(l+r)>>;//printf("%lld %lld %lld\n",l,r,mid);
if(check(mid)) r=mid-;
else l=mid+;
}
printf("%lld\n",cb*l-sb);
}
}
}
int main(){
int T=read();
while(T--){
n=read();m=read();
mx=cb=sb=cw=sw=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++){
g[i][j]=read();
mx=max(mx,(ll)g[i][j]);
if((i+j)&) cb++,sb+=g[i][j];
else cw++,sw+=g[i][j];
}
solve();
}
}
BZOJ 2756: [SCOI2012]奇怪的游戏 [最大流 二分]的更多相关文章
- BZOJ 2756 SCOI2012 奇怪的游戏 最大流
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2756 Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N ...
- BZOJ 2756: [SCOI2012]奇怪的游戏 网络流/二分
2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1594 Solved: 396[Submit][Stat ...
- bzoj 2756 [SCOI2012]奇怪的游戏 二分+网络流
2756:[SCOI2012]奇怪的游戏 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 4926 Solved: 1362[Submit][Stat ...
- bzoj 2756: [SCOI2012]奇怪的游戏
Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻 的格子,并使这两个数都加上 1. 现在 B ...
- BZOJ2756:[SCOI2012]奇怪的游戏(最大流,二分)
Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻 的格子,并使这两个数都加上 1. 现在 B ...
- BZOJ.2756.[SCOI2012]奇怪的游戏(二分 黑白染色 最大流ISAP)
题目链接 \(Description\) \(Solution\) 这种题当然要黑白染色.. 两种颜色的格子数可能相同,也可能差1.记\(n1/n2\)为黑/白格子数,\(s1/s2\)为黑/白格子权 ...
- bzoj 2756 [SCOI2012]奇怪的游戏【二分+最大流】
达成成就:为二分调参 !:多次memset的话要把数组大小开严格一点,否则会T 看到网格图,首先黑白染色. 注意到每次操作都是在一个黑格子和一个白格子上进行的,也就是说,最后黑格子数字和白格子数字和的 ...
- BZOJ2756 [SCOI2012]奇怪的游戏 【网络流 + 二分】
题目 Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻 的格子,并使这两个数都加上 1. 现在 Blinker 想知 ...
- BZOJ2756 [SCOI2012]奇怪的游戏 最大流
好久没有写博客了.不过这个博客也没有多少人看 最近在写网络流,为了加深理解,来写一两篇题解. 对整个棋盘进行黑白染色以后可以发现,一次操作就是让二分图的两个点的值分别 \(+1\). 这样,我们就可以 ...
随机推荐
- NodeJs之调试
关于调试 当我们只专注于前端的时候,我们习惯性F12,这会给我们带来安全与舒心的感觉. 但是当我们使用NodeJs来开发后台的时候,我想噩梦来了. 但是也别泰国担心,NodeJs的调试是很不方便!这是 ...
- 在PowerShell中使用curl(Invoke-WebRequest)
前言 习惯了windows的界面模式就很难转去命令行,甚至以命令行发家的git也涌现出各种界面tool.然而命令行真的会比界面快的多,如果你是一个码农. situation:接到需求分析bug,需要访 ...
- 【每日一linux命令4】常用参数:
下面所列的是常见的参数(选项)义: --help,-h 显示帮助信息 --version,-V ...
- MVVM TextBox的键盘事件
MVVM下RichTextBox的键盘回车事件设置为发送,不是回车 xmlns:i="http://schemas.microsoft.com/expression/2010/interac ...
- .Net Core MVC 网站开发(Ninesky) 2.3、项目架构调整-控制反转和依赖注入的使用
再次调整项目架构是因为和群友dezhou的一次聊天,我原来的想法是项目尽量做简单点别搞太复杂了,仅使用了DbContext的注入,其他的也没有写接口耦合度很高.和dezhou聊过之后我仔细考虑了一下, ...
- ASP.NET MVC开发日常一:SessionID合理清除
在MVC Web开发中临时存储数据一般会用到Session,Cookie,ViewBag,ViewData,TempData.每个的使用场景是不同,具体区别有空再补上. Session数据最敏感,最需 ...
- Java中,异常的处理及抛出
首先我们需要知道什么是异常? 常通常指,你的代码可能在编译时没有错误,可是运行时会出现异常.比如常见的空指针异常.也可能是程序可能出现无法预料的异常,比如你要从一个文件读信息,可这个文件不存在,程序无 ...
- GCC学习(1)之MinGW使用
GCC学习(1)之MinGW使用 因为后续打算分享一些有关GCC的使用心得的文章,就把此篇当作一个小预热,依此来了解下使用GNU工具链(gcc.gdb.make等)在脱离IDE的情况下如何开发以及涉及 ...
- Mono 3.2.3 Socket功能迎来一稳定的版本
由于兴趣自己业余时间一直在搞.net下面的通讯应用,mono的存在得以让.NET程序轻松运行在Linux之下.不过经过多尝试Socket相关功能在Mono下的表现并不理想.不管性能还是吞吐能力方面离我 ...
- 【腾讯Bugly干货分享】一步一步实现Android的MVP框架
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5799d7844bef22a823b3ad44 内容大纲: Android 开发 ...