BZOJ 2756 SCOI2012 奇怪的游戏 最大流
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2756
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
——————————————————————————————————————————————————
题意概述:
给出一个N*M的棋盘,每个格子有一个数,每次可以选择两个相邻的格子都+1。
问最少操作多少次可以让所有的数变得一样,如果无解输出-1。
分析:
发现只知道操作次数并没有什么用(因为你也不知道要怎么去填)。
假设最后的格子里的数是x。
每次操作对相邻的两个格子进行,发现可以把棋盘上的格子分开来,黑白染色。
抽象化表达:
假设有c1个白色格子,c2个黑色格子,一开始白色格子的和为s1,黑色格子的和为s2,那么假如答案可以成立,由分别对于黑白格子操作次数相同,有:
c1*x-s1=c2*x-s2 -> (c1-c2)*x=s1-s2
可以发现当c1=c2的时候x的值并不是唯一确定的,但是根据黑白染色的分析,可以发现这种情况下棋盘长宽中至少有一个是偶数,黑白可以两两配对,满足二分性质。
问题转化为判定。
建立源点S,汇点T,S向所有的白格子连边,容量为需要提升的值,黑格子向T连边,容量也为需要提升的值。
白点向周围的黑点连边,意义为这两个点一起提升的值,容量为inf。跑最大流看是否满流即可。
c1-c2!=0 -> x=(s1-s2)/(c1-c2),那么可以直接判定:是否大于等于最大格子,是否可以整除,是否可以判定成功。
小结:性质分析不出来怎么办?抽象成数学表达式再分析aaaaaaa!!!!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
#define inf (1e12+5)
using namespace std;
const int MAXN=;
typedef long long LL; int T,N,M,A[MAXN][MAXN];
int c1,c2,MAX; LL s1,s2;
struct NET{
static const int maxn=;
static const int maxm=;
struct edge{ int from,to,next; LL cap,flow; }E[maxm];
int n,S,T,first[maxn],np,d[maxn],gap[maxn],fl[maxn],cur[maxn];
NET(){ np=; }
void add_edge(int u,int v,LL c){
E[++np]=(edge){u,v,first[u],c,};
first[u]=np;
E[++np]=(edge){v,u,first[v],,};
first[v]=np;
}
int id(int x,int y){ return (x-)*M+y; }
void init(LL m){
memset(first,,sizeof(first));
np=,n=N*M+,S=n-,T=n;
LL re=;
for(int i=;i<=N;i++)
for(int j=;j<=M;j++){
if((i&)&&(j&)||!(i&)&&!(j&)){
add_edge(S,id(i,j),m-A[i][j]);
if(i-) add_edge(id(i,j),id(i-,j),inf);
if(j-) add_edge(id(i,j),id(i,j-),inf);
if(i+<=N) add_edge(id(i,j),id(i+,j),inf);
if(j+<=M) add_edge(id(i,j),id(i,j+),inf);
}
else add_edge(id(i,j),T,m-A[i][j]);
}
}
void BFS(){
queue<int>q;
for(int i=;i<=n;i++) d[i]=n;
d[T]=; q.push(T);
while(!q.empty()){
int i=q.front(); q.pop();
for(int p=first[i];p;p=E[p].next){
int j=E[p].to,pp=(p-^)+;
if(d[j]==n&&E[pp].cap>E[pp].flow) d[j]=d[i]+,q.push(j);
}
}
}
LL augment(){
LL flow=inf; int now=T;
while(now!=S){
flow=min(flow,E[fl[now]].cap-E[fl[now]].flow);
now=E[fl[now]].from;
}
now=T;
while(now!=S){
E[fl[now]].flow+=flow,E[(fl[now]-^)+].flow-=flow;
now=E[fl[now]].from;
}
return flow;
}
bool ISAP(){
memcpy(cur,first,sizeof(first));
memset(gap,,sizeof(gap));
BFS();
for(int i=;i<=n;i++) gap[d[i]]++;
int now=S; LL flow=;
while(d[S]<n){
if(now==T) flow+=augment(),now=S;
bool ok=;
for(int p=cur[now];p;p=E[p].next){
int j=E[p].to;
if(E[p].cap>E[p].flow&&d[j]+==d[now]){
ok=,cur[now]=fl[j]=p,now=j;
break;
}
}
if(!ok){
int minl=n;
for(int p=first[now];p;p=E[p].next){
int j=E[p].to;
if(E[p].cap>E[p].flow&&d[j]+<minl) minl=d[j]+;
}
if(--gap[d[now]]==) break;
gap[d[now]=minl]++;
cur[now]=first[now];
if(now!=S) now=E[fl[now]].from;
}
}
for(int p=first[S];p;p=E[p].next)
if(E[p].cap!=E[p].flow) return ;
for(int p=first[T],pp=(p-^)+;p;p=E[p].next,pp=(p-^)+)
if(E[pp].cap!=E[pp].flow) return ;
return ;
}
}net; void data_in()
{
scanf("%d%d",&N,&M);
for(int i=;i<=N;i++)
for(int j=;j<=M;j++)
scanf("%d",&A[i][j]);
c1=c2=MAX=,s1=s2=;
for(int i=;i<=N;i++)
for(int j=;j<=M;j++){
if((i&)&&(j&)||!(i&)&&!(j&)) s1+=A[i][j],c1++;
else s2+=A[i][j],c2++;
MAX=max(MAX,A[i][j]);
}
}
bool check(LL mid)
{
net.init(mid);
return net.ISAP();
}
void work()
{
if(c1==c2){
LL L=MAX,R=inf,mid,ans=-;
while(L<R){
mid=L+R>>;
if(check(mid)) R=mid,ans=mid;
else L=mid+;
}
if(ans!=-) cout<<(ans*N*M-s1-s2)/<<'\n';
else cout<<ans<<'\n';
}
else{
if((s1-s2)%(c1-c2)==&&(s1-s2)/(c1-c2)>=MAX){
LL ans=(s1-s2)/(c1-c2);
if(check(ans)) cout<<(ans*N*M-s1-s2)/<<'\n';
else cout<<-<<'\n';
}
else cout<<-<<'\n';
}
}
int main()
{
scanf("%d",&T);
while(T--){
data_in();
work();
}
return ;
}
BZOJ 2756 SCOI2012 奇怪的游戏 最大流的更多相关文章
- BZOJ 2756: [SCOI2012]奇怪的游戏 [最大流 二分]
2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 3352 Solved: 919[Submit][Stat ...
- 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 ...
- BZOJ.2756.[SCOI2012]奇怪的游戏(二分 黑白染色 最大流ISAP)
题目链接 \(Description\) \(Solution\) 这种题当然要黑白染色.. 两种颜色的格子数可能相同,也可能差1.记\(n1/n2\)为黑/白格子数,\(s1/s2\)为黑/白格子权 ...
- bzoj 2756 [SCOI2012]奇怪的游戏【二分+最大流】
达成成就:为二分调参 !:多次memset的话要把数组大小开严格一点,否则会T 看到网格图,首先黑白染色. 注意到每次操作都是在一个黑格子和一个白格子上进行的,也就是说,最后黑格子数字和白格子数字和的 ...
- BZOJ2756:[SCOI2012]奇怪的游戏(最大流,二分)
Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻 的格子,并使这两个数都加上 1. 现在 B ...
- BZOJ2756 [SCOI2012]奇怪的游戏 最大流
好久没有写博客了.不过这个博客也没有多少人看 最近在写网络流,为了加深理解,来写一两篇题解. 对整个棋盘进行黑白染色以后可以发现,一次操作就是让二分图的两个点的值分别 \(+1\). 这样,我们就可以 ...
- 【BZOJ-2756】奇怪的游戏 最大流 + 分类讨论 + 二分
2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 2925 Solved: 792[Submit][Stat ...
随机推荐
- 课时59.体验css(理解)
我们想做这样一个样式,应该怎么做? 分析: 有一个标题(h1),还有一些段落(p) 标题是居中的,段落也是居中的,所以我们可以设置h标签和p标签居的align属性等于center来实现 标题和段落都有 ...
- BFC、IFC、GFC、FFC
原文地址:https://www.xingkongbj.com/blog/css/fc.html FC FC的全称是:Formatting Contexts,是W3C CSS2.1规范中的一个概念.它 ...
- ATK-DataPortal 设计框架(三)
边界清晰.服务自治.契约共享.基于策略的兼容性,是面向对向设计时四个基本原则,我们的应用可能分布在不同的环境之中,应用可能在同一服务器中,也可能在不同的网络环境中,保证框架的基类能在不同环境中仍然可用 ...
- ZLG zigbee 虚拟串口配置
一.设置网关工作模式: 在ZNetCom Utility工具中,将设置网关工作模式为 Real COM 模式 启动 ZNetCom Utility 搜索设备 获得设备信息 修改工作模式为:real c ...
- 关于mysql8.0.11版本在win10安装
新的mysql版本没有.exe文件一键安装,网上找了教程,自己搞了下 首先是在菜鸟教程 http://www.runoob.com/mysql/mysql-install.html 根据它的提示下载w ...
- 关于J2EE里面getContextPath()和getRealPath()的区别
一直老搞不清楚这两个方法的区别,只知道他们都是拿来获取地址的.今天特意写了个小demo试了一下,代码如下: @Override protected void service(HttpServletRe ...
- (转)阿里巴巴Druid数据源及使用
原文链接:https://blog.csdn.net/yanguo110/article/details/68944659 第一部分:数据源的集中比较. 目前常用的数据源主要有c3p0.dbcp.pr ...
- Struts2拦截器说明
有关于Struts2的拦截器的原理 在此共设置了两个拦截器,firstInterception.SecondInterception package struts2_inteception; publ ...
- dom4j里面封装方法的操作
animal.xml <?xml version="1.0" encoding="UTF-8"?><animal> <cat ...
- npm 如何提升最新版本
首先我们查看一下npm当前版本,打开cmd 运行命令: npm -v 如果不是最新版本,运行一下代码即可. npm install -g npm 这样npm就更新到最新版本了. 如果想更新到指定版本, ...