Wpremig和Jhadgre的藏宝图(最大流+二分)
Wpremig和Jhadgre的藏宝图
题目链接:https://ac.nowcoder.com/acm/contest/333/M
Description:
Jhadgre在生日那天收到了一张神秘的藏宝图,于是他决定和Wpremig分享这张藏宝图,并且去寻宝!
这张藏宝图上总共有N行,每行有M个格子,共N*M个格子,每个格子上写了一个数字。
藏宝图上写了一段字:神秘的有缘人啊,这些格子已经被其他人挖过了,我已经替你标出了所有格子被挖到的深度,并且在这个宝藏上加了一个魔法,只要你把所有格子都挖到同一个深度,宝藏自然就会出现。
这看似是一个很简单的问题,只要知道现在最深的那个格子,其他格子都挖到这个深度,就是最快的方式了。然而Wpremig和Jhadgre却发现,还有一句话:我知道你们有两个人,所以你们在挖的时候必须两个人同时各挖一个格子,并且这两个格子必须相邻!
这就比较尴尬了,Wpremig和Jhadgre很不高兴,这是送礼呢还是膈应人呢?不挖了!
虽然这样说,但是人总是会遵循“真香定理”。在几天后Wpremig和Jhadgre还是决定去挖宝藏,现在他们在出发前想知道,最少需要挖多少次才能获得宝藏呢?(假设每次一个人挖一个格子可以将这个格子的深度+1)
Input:
第一行一个整数T表示数据组数(T<=10)
对于每组数据,第一行两个整数N,M。
接下去N行每行M个整数。
保证 T<=10,1<=N,M<=40,所有数为正整数且小于1000000000
Output:
对于每组数据输出最少的挖掘次数,若无论如何都不能获得宝藏,则输出-1;
Sample Input:
1
2 2
1 2
2 3
Sample Output:
2
题解:
这里挖格子必须两个相邻的格子一起挖,我们发现二分图也是相邻的格子在两边,那么我们就可以首先将图进行黑白染色,之后令黑在左,白在右进行构图。
每一个黑格子肯定连向与它相邻的白格子,现在来确定容量。
我们假定最后的深度为x,设黑色格子数量为black,白色格子数量为white,黑色格子目前的数量和为sumblack,白色格子的数量和为sumwhile,那么最后的状态就有:
black*x-sumblack = white*x-sumwhite,最后有(black-white)*x = sumblack-sumwhite。
当black=white时,首先要有两个sum相等,然后就可以check求出x最优值;如果black!=white,我们可以将x接出来,然后checkx看是否合法。
对于check就是边容量的问题,这里的x是最大深度,那么我们与源点以及汇点连接的边权就为x减去目前深度就好了。
我一开始就是想直接checkx,但是发现黑白格子数量会影响到x的取值= =
代码如下:
#include <bits/stdc++.h>
#define s 0
#define t 1700
#define INF 1e18
using namespace std;
typedef long long ll;
const int N = ,M = ;
int T,n,m,tot,mx;
ll sum1,sum2;
ll head[],d[],cnt[];
int a[N][M],color[N][M];
int dx[]={,,,-};
int dy[]={,,-,};
struct Edge{
ll c;
int v,next;
}e[];
void adde(int u,int v,ll c){
e[tot].v=v;e[tot].next=head[u];e[tot].c=c;head[u]=tot++;
e[tot].v=u;e[tot].next=head[v];e[tot].c=;head[v]=tot++;
}
bool ok(int x,int y){
return x>= && x<=n && y>= && y<=m;
}
bool bfs(int S,int T){
memset(d,,sizeof(d));d[S]=;
queue <ll > q;q.push(S);
while(!q.empty()){
ll u=q.front();q.pop();
for(int i=head[u];i!=-;i=e[i].next){
int v=e[i].v;
if(!d[v] && e[i].c>){
d[v]=d[u]+;
q.push(v);
}
}
}
return d[T]!=;
}
ll dfs(int S,ll A){
ll flow=,f;
if(S==t || A==) return A;
for(ll i=head[S];i!=-;i=e[i].next){
ll v=e[i].v;
if(d[v]!=d[S]+) continue ;
f=dfs(v,min(A,e[i].c));
if(f){
e[i].c-=f;
e[i^].c+=f;
flow+=f;
A-=f;
if(A==) break;
}
}
if(!flow) d[S]=-;
return flow;
}
ll Dinic(){
ll max_flow=;
while(bfs(,t)){
max_flow+=dfs(,INF);
}
return max_flow;
}
void build(ll x){
tot=;memset(head,-,sizeof(head));
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
if(color[i][j]==) adde(s,(i-)*m+j,x-a[i][j]);
else adde((i-)*m+j,t,x-a[i][j]);
if(color[i][j]==) continue ;
for(int k=;k<;k++){
int nowx = i+dx[k],nowy = j+dy[k];
if(ok(nowx,nowy)) adde((i-)*m+j,(nowx-)*m+nowy,INF);
}
}
}
}
void dfs_col(int x,int y,int col){
color[x][y]=col;
cnt[col]++;
if(col==) sum1+=a[x][y];
if(col==) sum2+=a[x][y];
for(int i=;i<;i++){
ll nowx = x+dx[i],nowy = y+dy[i];
if(ok(nowx,nowy)&&!color[nowx][nowy]) dfs_col(nowx,nowy,-col);
}
}
int check(ll x){
build(x);
ll flow = Dinic();
for(int i=head[s];i!=-;i=e[i].next) if(e[i].c) return ;
return ;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
mx = ;
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
scanf("%d",&a[i][j]);
mx=max(a[i][j],mx);
}
}
memset(color,,sizeof(color));
memset(cnt,,sizeof(cnt));
sum1 = sum2 = ;
dfs_col(,,);
if((n*m)%==){
if(sum1!=sum2){
printf("-1\n");
continue ;
}
ll l=mx,r=1e13,mid;
while(l<r){
mid=l+r>>;
if(check(mid)) r=mid;
else l=mid+;
}
if(l==1e13) printf("-1\n");
else printf("%lld\n",(l*m*n-sum1-sum2)/);
}else{
ll x = (sum1-sum2)/(cnt[]-cnt[]);
if(check(x)) printf("%lld\n",(x*m*n-sum1-sum2)/);
else printf("-1\n");;
}
}
return ;
}
Wpremig和Jhadgre的藏宝图(最大流+二分)的更多相关文章
- HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)
HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...
- Risk UVA - 12264 拆点法+最大流+二分 最少流量的节点流量尽量多。
/** 题目:Risk UVA - 12264 链接:https://vjudge.net/problem/UVA-12264 题意:给n个点的无权无向图(n<=100),每个点有一个非负数ai ...
- BZOJ-3130 费用流 (听题目胡扯丶裸最大流) 二分判定+最大流+实数精度乱搞
DCrusher爷喜欢A我做的水题,没办法,只能A他做不动的题了.... 3130: [Sdoi2013]费用流 Time Limit: 10 Sec Memory Limit: 128 MBSec ...
- BZOJ-1305 dance跳舞 建图+最大流+二分判定
跟随YveH的脚步又做了道网络流...%%% 1305: [CQOI2009]dance跳舞 Time Limit: 5 Sec Memory Limit: 162 MB Submit: 2119 S ...
- poj 2112 floyd+Dinic最大流+二分最小值
题目大意是: K台挤奶机器,C头牛,K不超过30,C不超过200,每台挤奶机器最多可以为M台牛工作,给出这些牛和机器之间,牛和牛之间,机器与机器之间的距离,在保证让最多的牛都有机器挤奶的情况下,给出其 ...
- hdu 3228 (最大流+二分)
题意:一共有N个城市,一些城市里有金矿,一些城市里有仓库,金矿和仓库都有一个容量,有M条边,每条边是双向的,有一个权值,求将所有金矿里的储量都运送到仓库中,所需要经过的道路中,使最大的权值最小 思路: ...
- BZOJ2406矩阵——有上下界的可行流+二分答案
题目描述 输入 第一行两个数n.m,表示矩阵的大小. 接下来n行,每行m列,描述矩阵A. 最后一行两个数L,R. 输出 第一行,输出最小的答案: 样例输入 2 2 0 1 2 1 0 1 样例输出 1 ...
- bzoj 3597 [Scoi2014] 方伯伯运椰子 - 费用流 - 二分答案
题目传送门 传送门 题目大意 给定一个费用流,每条边有一个初始流量$c_i$和单位流量费用$d_i$,增加一条边的1单位的流量需要花费$b_i$的代价而减少一条边的1单位的流量需要花费$a_i$的代价 ...
- BZOJ4669抢夺(费用流+二分答案)
题目描述 大战将至, 美国决定实行计划经济.美国西部总共有 N 个城市,编号 为 0 ∼ N − 1,以及 M 条道路,道路是单向的.其中城市 0 是一个大城 市,里面住着 K 个人,而城市 N − ...
随机推荐
- python3 练习题100例 (十一)
题目十一:举例证明角谷猜想:以一个正整数N为例,如果N为偶数,就将它变为N/2,如果除后变为奇数,则将它乘3加1(即3N+1).不断重复这样的运算,经过有限步后,一定可以得到1. #!/usr/bin ...
- C# FTP上传文件时出现"应 PASV 命令的请求,服务器返回了一个与 FTP 连接地址不同的地址。"的错误
FTP上传文件时出现"应 PASV 命令的请求,服务器返回了一个与 FTP 连接地址不同的地址."的错误 解决方法是在原代码上增加这句话 reqFTP.UsePassive = f ...
- shell -- for、while用法
#数字段形式for i in {1..10}do echo $idone #详细列出(字符且项数不多)for File in 1 2 3 4 5do echo $Filedone #对存在的 ...
- ubuntu 把软件源修改为国内源
国内有很多Ubuntu的镜像源,比如:阿里源.网易源等,还有很多教育网的源,比如:清华源.中科大源等. 这里以清华源为例讲解如何修改Ubuntu 18.04里面默认的源. 修改步骤 第一步:备份原始源 ...
- 初探 Qt Opengl【2】
最近在研究QOPengl QGraphicsView QGraphicsItemQGraphicsScene不过也只是皮毛,也不是做什么技术贴,就是记录一下自己在其中遇到的问题,和自己新学到的东西. ...
- 第十五篇 Python之文件处理
一 文件操作 介绍 计算机系统分为:计算机硬件,操作系统,应用程序三部分. 我们用python或其他语言编写的应用程序若想要把数据永久保存下来,必须要保存于硬盘中,这就涉及到应用程序要操作硬件,众所 ...
- FlaskWeb开发从入门到放弃(二)
第5章 章节五 01 内容概要 02 内容回顾 03 面向对象相关补充:metaclass(一) 04 面向对象相关补充:metaclass(二) 05 WTforms实例化流程分析(一) 06 WT ...
- weblogic中配置自定义filter和servlet
情景:最近公司产品要接入其它厂商的单点服务器,本来我是在Tomcat上进行测试,使用的是spring boot 的注解方式@webFilter和@webServlet注解写过滤器和servlet类,启 ...
- 1107 Social Clusters (30 分)(并查集)
并查集的基本应用 #include<bits/stdc++.h> using namespace std; ; vector<int>vec[N]; int p[N]; con ...
- ThinkPHP5项目目录规划实践
ThinkPHP5安装后(或者下载后的压缩文件解压后)可以看到下面的目录结构: tp5├─application 应用目录 ├─extend 扩展类库目录(可定义) ├─pu ...