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 − ...
随机推荐
- python学习——基本数据类型
一.运算符 1.算术运算: 2.比较运算 3.赋值运算 4.逻辑运算 5.成员运算 二.基本数据类型 1.数字 1.1 整形数字和长整形数字:在32位机器上,整数的位数为32位,取值范围为-2**31 ...
- python3 练习题100例 (二十五)打印一个n层金字塔
题目内容: 打印一个n层(1<n<20)金字塔,金字塔由“+”构成,塔尖是1个“+”,下一层是3个“+”,居中排列,以此类推. 注意:每一行的+号之后均无空格,最后一行没有空格. 输入格式 ...
- 常用 css html 样式
CSS基础必学列表 CSS width宽度 CSS height高度 CSS border边框 CSS background背景 CSS sprites背景拼合 CSS float浮动 CSS mar ...
- 【转】mui 通过JSON动态的生成列表
<script type="text/template" id="radio-tigan"> <%for(var i=0;i<recor ...
- 5 多线程 模拟qq聊天
1.多线程思路 使用多线程完成一个全双工的QQ聊天程序 2.版本1:程序小框架 #1.收数据,然后打印 def recvData(): pass #2.检测键盘,发数据 def sendData(): ...
- Java重写构造方法
public class TestSuper { public static void main(String[] args) { new ChildClass("alex", 1 ...
- SQL Server 2005 导出包含(insert into)数据的SQL脚本 (使用存储过程) 分类: 数据库
CREATE PROCEDURE dbo.UspOutputData @tablename sysname AS ) ) ) declare @xtype tinyint declare @name ...
- 在Linux中安装和配置OpenVPN Server的最简便方法!
本文介绍了如何在基于RPM和DEB的系统中安装和配置OpenVPN服务器.我们在本文中将使用一个名为openvpn-install的脚本,它使整个OpenVPN服务器的安装和配置过程实现了自动化.该脚 ...
- 云计算之路-阿里云上:Web服务器请求到达量突降
今天下午遇到了自使用阿里云以来首次遇到的新情况——http.sys的ArrivalRate突降(说明请求到达IIS的请求数量少了),而且SLB中的3台ECS都出现了这个问题. 1. 10.161.24 ...
- 《Cracking the Coding Interview》读书笔记
<Cracking the Coding Interview>是适合硅谷技术面试的一本面试指南,因为题目分类清晰,风格比较靠谱,所以广受推崇. 以下是我的读书笔记,基本都是每章的课后习题解 ...