炮塔

Time Limit: 10 Sec  Memory Limit: 256 MB

Description

  

Input

  

Output

  一行一个整数表示答案。

Sample Input

  4 5
  0 0 -2 0 0
  -4 0 5 4 0
  0 -4 3 0 6
  9 0 0 -1 0

Sample Output

  12

HINT

  

Main idea

  给定若干固定方向的炮台,以及若干位置的敌人,炮台可以杀掉对应方向上从该位置到底的其中一个位置的敌人,要求炮台位置和消灭的敌人位置连线,连线不能有重叠,询问最多能消灭几个敌人。

Solution

  我们发现,相交的连线其实就是给出了炮台之间的路径。我们来处理如何解决无可走路径的问题,显然想到了最小割。

  横向炮台或纵向炮台之间是没有影响的。所以显然可以构建一张二分图。

  那么我们如何确定容量呢?我们可以令一条 (u->v) 的割边表示选择了u这个点。方便处理连边上下或左右攻击的炮台,连边方向应该一致。然后我们连边时先找到一条可攻击位置上的最大贡献,设最大贡献为Max,然后连边时容量用Max-val,就表示它会损失这么多的价值。注意到这样连边的话,在最边界上的点是没有连边的。但是并不会影响答案,为什么呢?我们这么考虑:如果我们选择了最边界的点,那么这个位置的敌人数必然是最多的,如果不是最多的话(也就是说还有其它点人数更多)显然连到边界不可能是最优的,因为连边界就可能阻断了更多其它炮台攻击方案的可能性。这就表示了,若选择边界,则必然边界贡献最多,那么如果连边了,容量也应该是0,综上所述不会影响答案。

  我们这样连完了边,但发现还是会有一些问题。如果出现这种情况,就会有一些Bug:

  这样就会影响了答案。怎么处理呢?我们发现问题只能涉及一行一列,只要令路径只能“拐一次弯”就可以解决。所以我们可以再将点拆为横向点和纵向点,横向点向纵向点连INF的边,纵向点没有边连向横向点即可。

  这样的话复杂度就是O(maxflow(n×m,n×m)),成功了解决了问题!\(≧▽≦)/

Code

 #include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std; const int ONE = ;
const int INF = ; int n,m;
int S,T;
int Ans;
int a[][],Max;
int next[ONE],first[ONE],go[ONE],w[ONE],tot;
int q[],Dep[ONE],E[ONE],tou,wei;
#define id(i,j) (i-1)*m+j int get()
{
int res,Q=; char c;
while( (c=getchar())< || c>)
if(c=='-')Q=-;
if(Q) res=c-;
while((c=getchar())>= && c<=)
res=res*+c-;
return res*Q;
} void Add(int u,int v,int z)
{
next[++tot]=first[u]; first[u]=tot; go[tot]=v; w[tot]=z;
next[++tot]=first[v]; first[v]=tot; go[tot]=u; w[tot]=;
} int Bfs()
{
memset(Dep,,sizeof(Dep));
tou=; wei=;
q[]=S; Dep[S]=;
for(int u=S;u<=T;u++) E[u]=first[u];
while(tou < wei)
{
int u=q[++tou];
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(Dep[v] || !w[e]) continue;
Dep[v] = Dep[u] + ;
q[++wei] = v;
}
}
return Dep[T] > ;
} int Dfs(int u,int Limit)
{
if(u==T || !Limit) return Limit;
int flow=,f;
for(int &e=E[u]; e; e=next[e])
{
int v=go[e];
if(Dep[v]!=Dep[u]+ || !w[e]) continue;
f=Dfs(v,min(w[e],Limit));
w[e] -= f;
w[((e-)^)+] += f;
Limit -= f;
flow += f;
if (!Limit) break;
}
return flow;
} int main()
{
n=get(); m=get();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
a[i][j] = get();
} int PD=n*m;
S=; T=*PD+;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
if(a[i][j] == -)
{
Max = a[i][j] = ;
Add(S,id(i,j),INF);
for(int k=i-;k>=;k--) Max = max(Max, a[k][j]);
for(int k=i;k>=+;k--) Add(id(k,j), id(k-,j), Max-a[k][j]);
Ans += Max;
} else
if(a[i][j] == -)
{
Max = a[i][j] = ;
Add(S,id(i,j),INF);
for(int k=i+;k<=n;k++) Max = max(Max, a[k][j]);
for(int k=i;k<=n-;k++) Add(id(k,j), id(k+,j), Max-a[k][j]);
Ans += Max;
} else
if(a[i][j] == -)
{
Max = a[i][j] = ;
Add(id(i,j)+PD,T,INF);
for(int k=j-;k>=;k--) Max = max(Max, a[i][k]);
for(int k=j;k>=+;k--) Add(id(i,k-)+PD, id(i,k)+PD, Max-a[i][k]);
Ans += Max;
} else
if(a[i][j] == -)
{
Max = a[i][j] = ;
Add(id(i,j)+PD,T,INF);
for(int k=j+;k<=m;k++) Max = max(Max, a[i][k]);
for(int k=j;k<=m-;k++) Add(id(i,k+)+PD, id(i,k)+PD, Max-a[i][k]);
Ans += Max;
} else
{
Add(id(i,j), id(i,j)+PD, INF);
}
} while(Bfs()) Ans-=Dfs(S,INF); printf("%d",Ans);
}

【BZOJ4657】tower [网络流]的更多相关文章

  1. BZOJ4657 : tower

    显然只有横向和纵向的两个炮塔才有可能冲突. 考虑最小割,将每个炮塔所有能攻击到的位置建点,相邻之间连无穷的边,表示前缀和关系,即选了一个点,就必须要选所有比它近的点. 属于横向炮塔的点向$S$连边,容 ...

  2. [网络流]BZOJ4657 最小割约束

    题面: DescriptionNick最近在玩一款很好玩的游戏,游戏规则是这样的:有一个n*m的地图,地图上的每一个位置要么是空地,要么是炮塔,要么是一些BETA狗,Nick需要操纵炮塔攻击BETA狗 ...

  3. E - tower HYSBZ - 4657 (网络流割点)

    题目链接:https://cn.vjudge.net/contest/281959#problem/E 题目大意:中文题目 具体思路:首先,有矛盾的时候就是两个导弹的运动轨迹会相交的时候,那么我们可以 ...

  4. TYVJ 1935 拆点网络流

    思路: 就是一个多重匹配 把每个防御塔拆成 拆成第j次 发射的导弹 跑个网络流 //By SiriusRen #include <cmath> #include <queue> ...

  5. plain framework 1 网络流 缓存数据详解

    网络流是什么?为什么网络流中需要存在缓存数据?为什么PF中要采用缓存网络数据的机制?带着这几个疑问,让我们好好详细的了解一下在网络数据交互中我们容易忽视以及薄弱的一块.该部分为PF现有的网络流模型,但 ...

  6. Tower是个不错的项目管理开放平台

    简单,易用,轻量级,挺多大项目都在用. 目前公司的项目也在使用,但是从高层到底下,随意惯了,最终没有用起来. 感觉适合年轻激情的创业公司团队来使用. 附上地址:https://tower.im/

  7. 网络流模板 NetworkFlow

    身边的小伙伴们都在愉快地刷网络流,我也来写一发模板好了. Network Flow - Maximum Flow Time Limit : 1 sec, Memory Limit : 65536 KB ...

  8. COGS732. [网络流24题] 试题库

    «问题描述:假设一个试题库中有n道试题.每道试题都标明了所属类别.同一道题可能有多个类别属性.现要从题库中抽取m 道题组成试卷.并要求试卷包含指定类型的试题.试设计一个满足要求的组卷算法.«编程任务: ...

  9. dwarf tower

    dwarf tower(dwarf.cpp/c/pas)[问题描述]Vasya在玩一个叫做"Dwarf Tower"的游戏,这个游戏中有n个不同的物品,它们的编号为1到n.现在Va ...

随机推荐

  1. c++ constructor, copy constructor, operator =

    // list::push_back #include <iostream> #include <list> class element{ private: int numbe ...

  2. 每天一个Linux命令(13):apt命令

    apt-get和apt-cache命令是Debian Linux发行版中的APT软件包管理工具.所有基于Debian的发行都使用这个包管理系统.deb包可以把一个应用的文件包在一起,大体就如同Wind ...

  3. Uniy 组件式泛型单例模式

    我们知道,在Unity中,所有对象脚本都必须继承MonoBehavior脚本,才能使用Unity内置的脚本功能; 通常我们可以用静态类来取代单例模式,但是静态类方法的缺点是,它们必须继承最底层的类-- ...

  4. 开发react的一些记录

    1.keyboard事件返回的对象SyntheticKeyboardEvent全部是null 解决方法:SyntheticKeyboardEvent的type,which,timeStamp可以得到你 ...

  5. 《python机器学习—预测分析核心算法》:理解数据

    参见原书2.1-2.2节 新数据集就像一个包装好的礼物,它充满了承诺和希望! 但是直到你打开前,它都保持神秘! 一.基础问题的架构.术语,机器学习数据集的特性 通常,行代表实例,列代表属性特征 属性, ...

  6. Django源码分析之权限系统_擒贼先擒王

    乍见 Django内置的权限系统已经很完善了,加上django-guardian提供的功能,基本上能满足大部分的权限需求.暂且不说django-guardian,我们先来看下Django内置的权限系统 ...

  7. 【读书笔记】2_增强学习中的Q-Learning

    本文为Thomas Simonini增强学习系列文章笔记或读后感,原文可以直接跳转到medium系列文章. 主要概念为: Q-Learning,探讨其概念以及用Numpy实现 我们可以将二维游戏想象成 ...

  8. php处理三级分类数据

    <?php // 链接数据库 $link = mysqli_connect('localhost','root','root'); if($link == null){ exit; } mysq ...

  9. php自学笔记2

    php运行原理: 如果请求服务器上的资源是html网页,服务器直接将网页响应给客户端浏览器: 如果请求服务器上的资源是php,服务器先解释执行php,解释为标准的html代码响应给客户端浏览器.php ...

  10. shell 中的expect 用法

    expect一般用于实现用脚本来自动远程登录,对远程机器执行相关操作 测试机上的expect目录一般在/usr/bin/expect路径 下面是从网上查询的用法总结: 1. expect中的判断语句: ...