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的藏宝图(最大流+二分)的更多相关文章

  1. HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)

    HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...

  2. Risk UVA - 12264 拆点法+最大流+二分 最少流量的节点流量尽量多。

    /** 题目:Risk UVA - 12264 链接:https://vjudge.net/problem/UVA-12264 题意:给n个点的无权无向图(n<=100),每个点有一个非负数ai ...

  3. BZOJ-3130 费用流 (听题目胡扯丶裸最大流) 二分判定+最大流+实数精度乱搞

    DCrusher爷喜欢A我做的水题,没办法,只能A他做不动的题了.... 3130: [Sdoi2013]费用流 Time Limit: 10 Sec Memory Limit: 128 MBSec ...

  4. BZOJ-1305 dance跳舞 建图+最大流+二分判定

    跟随YveH的脚步又做了道网络流...%%% 1305: [CQOI2009]dance跳舞 Time Limit: 5 Sec Memory Limit: 162 MB Submit: 2119 S ...

  5. poj 2112 floyd+Dinic最大流+二分最小值

    题目大意是: K台挤奶机器,C头牛,K不超过30,C不超过200,每台挤奶机器最多可以为M台牛工作,给出这些牛和机器之间,牛和牛之间,机器与机器之间的距离,在保证让最多的牛都有机器挤奶的情况下,给出其 ...

  6. hdu 3228 (最大流+二分)

    题意:一共有N个城市,一些城市里有金矿,一些城市里有仓库,金矿和仓库都有一个容量,有M条边,每条边是双向的,有一个权值,求将所有金矿里的储量都运送到仓库中,所需要经过的道路中,使最大的权值最小 思路: ...

  7. BZOJ2406矩阵——有上下界的可行流+二分答案

    题目描述 输入 第一行两个数n.m,表示矩阵的大小. 接下来n行,每行m列,描述矩阵A. 最后一行两个数L,R. 输出 第一行,输出最小的答案: 样例输入 2 2 0 1 2 1 0 1 样例输出 1 ...

  8. bzoj 3597 [Scoi2014] 方伯伯运椰子 - 费用流 - 二分答案

    题目传送门 传送门 题目大意 给定一个费用流,每条边有一个初始流量$c_i$和单位流量费用$d_i$,增加一条边的1单位的流量需要花费$b_i$的代价而减少一条边的1单位的流量需要花费$a_i$的代价 ...

  9. BZOJ4669抢夺(费用流+二分答案)

    题目描述 大战将至, 美国决定实行计划经济.美国西部总共有 N 个城市,编号 为 0 ∼ N − 1,以及 M 条道路,道路是单向的.其中城市 0 是一个大城 市,里面住着 K 个人,而城市 N − ...

随机推荐

  1. 怎么用Python Flask模板jinja2在网页上打印显示16进制数?

    问题:Python列表(或者字典等)数据本身是10进制,现在需要以16进制输出显示在网页上 解决: Python Flask框架中 模板jinja2的If 表达式和过滤器 假设我有一个字典index, ...

  2. python基础数据类型的相关知识点

    1.字符串的函数join >>> s = "Hello" >>> s1 = s.join("你好")#将字符串Hello插入 ...

  3. linux中常用命令总结

    一关机/重启/注销 关机 shutdown -h now //立即关机 重启 shutdown -r now //立即重启 reboot 重新启动 注销 logout //退出注销当前用户窗口 exi ...

  4. 【Java】关于Spring框架的总结 (二)

    上文提到了 Spring 的 IoC 特性和 AOP 特性,只提到个别的实现方法.本文将对 IoC 和 AOP 其他方法进行讲解. 多种方式实现依赖注入 1.设值注入 上文中使用的注入方法:通过 se ...

  5. 理解Canvas像素边界

    大家看下面的例子 var context = document.getElementById('canvas').getContext('2d'); context.lineWidth = 1; co ...

  6. hdu1233 继续畅通工程 (最小生成树——并查集)

    还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

  7. 谷歌面试官经典作品(CTCI)目录

    1.1 判断一个字符串中的字符是否唯一 1.2 字符串翻转 1.3 去除字符串中重复字符 1.8 利用已知函数判断字符串是否为另一字符串的子串 2.1 从链表中移除重复结点 2.2 实现一个算法从一个 ...

  8. Anytime项目开发记录1

    关于Android APP 应用设计,我并没有接受过系统的学习. 下面,是按照我一直以来的方法来进行编辑. 由于在程序开始之前并没有画类图,这里简单的讲述一下程序是如何设计的. 自己实现了一个Appl ...

  9. 数据结构(python语言)目录链接

    第一章 准备工作 课时0:0.数据结构(python语言) 基本概念 算法的代价及度量!!!

  10. NO7——二分

    int binsearch(int *t,int k,int n) {//t为数组,k是要查找的数,n为长度,此为升序 ,high = n,mid; while(low<=high) { mid ...