【BZOJ4657】tower [网络流]
炮塔
Time Limit: 10 Sec Memory Limit: 256 MB
Description
Input
Output
一行一个整数表示答案。
Sample Input
0 0 -2 0 0
-4 0 5 4 0
0 -4 3 0 6
9 0 0 -1 0
Sample Output
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 [网络流]的更多相关文章
- BZOJ4657 : tower
显然只有横向和纵向的两个炮塔才有可能冲突. 考虑最小割,将每个炮塔所有能攻击到的位置建点,相邻之间连无穷的边,表示前缀和关系,即选了一个点,就必须要选所有比它近的点. 属于横向炮塔的点向$S$连边,容 ...
- [网络流]BZOJ4657 最小割约束
题面: DescriptionNick最近在玩一款很好玩的游戏,游戏规则是这样的:有一个n*m的地图,地图上的每一个位置要么是空地,要么是炮塔,要么是一些BETA狗,Nick需要操纵炮塔攻击BETA狗 ...
- E - tower HYSBZ - 4657 (网络流割点)
题目链接:https://cn.vjudge.net/contest/281959#problem/E 题目大意:中文题目 具体思路:首先,有矛盾的时候就是两个导弹的运动轨迹会相交的时候,那么我们可以 ...
- TYVJ 1935 拆点网络流
思路: 就是一个多重匹配 把每个防御塔拆成 拆成第j次 发射的导弹 跑个网络流 //By SiriusRen #include <cmath> #include <queue> ...
- plain framework 1 网络流 缓存数据详解
网络流是什么?为什么网络流中需要存在缓存数据?为什么PF中要采用缓存网络数据的机制?带着这几个疑问,让我们好好详细的了解一下在网络数据交互中我们容易忽视以及薄弱的一块.该部分为PF现有的网络流模型,但 ...
- Tower是个不错的项目管理开放平台
简单,易用,轻量级,挺多大项目都在用. 目前公司的项目也在使用,但是从高层到底下,随意惯了,最终没有用起来. 感觉适合年轻激情的创业公司团队来使用. 附上地址:https://tower.im/
- 网络流模板 NetworkFlow
身边的小伙伴们都在愉快地刷网络流,我也来写一发模板好了. Network Flow - Maximum Flow Time Limit : 1 sec, Memory Limit : 65536 KB ...
- COGS732. [网络流24题] 试题库
«问题描述:假设一个试题库中有n道试题.每道试题都标明了所属类别.同一道题可能有多个类别属性.现要从题库中抽取m 道题组成试卷.并要求试卷包含指定类型的试题.试设计一个满足要求的组卷算法.«编程任务: ...
- dwarf tower
dwarf tower(dwarf.cpp/c/pas)[问题描述]Vasya在玩一个叫做"Dwarf Tower"的游戏,这个游戏中有n个不同的物品,它们的编号为1到n.现在Va ...
随机推荐
- SSH公钥认证(码云)
开发者向码云版本库写入最常用到的协议是 SSH 协议,因为 SSH 协议使用公钥认证,可以实现无口令访问,而若使用 HTTPS 协议每次身份认证时都需要提供口令.使用 SSH 公钥认证,就涉及到公钥的 ...
- Linux-获得命令帮助man
date:显示当前系统时间,修改时间 clock,hwclock:显示硬件时间 cal:calendar,查看日历 计时器靠晶体振荡器来完成计时 Linux: 实时时钟,rtc,real time c ...
- 详说大数据计算的可类化Classable
可类化(Classable)是Laxcus大数据管理系统提供的一项基础功能,它能够将类转化为一串字节数组,或者逆向将字节数组转化为一个类.这项功能与JAVA提供的序列化(Serializable)非常 ...
- adb usage
使用安卓调试及自动化,不可避免的要使用adb,说明看起来很麻烦,进行简单记录,以便时候不时之需. usb连接手机调试就很简单了.首先,在手机端开启usb调试,即点击安卓版本项7次,就可以显示开发者菜单 ...
- 剑指offer-矩形覆盖10
题目描述 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形.请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? # -*- coding:utf-8 -*- class S ...
- NLP系列-中文分词(基于词典)
中文分词概述 词是最小的能够独立活动的有意义的语言成分,一般分词是自然语言处理的第一项核心技术.英文中每个句子都将词用空格或标点符号分隔开来,而在中文中很难对词的边界进行界定,难以将词划分出来.在汉语 ...
- sqlite sql语句关键字GROUP BY的理解
第一遍看GROUP BY的介绍时,没看懂. SQLite 的 GROUP BY 子句用于与 SELECT 语句一起使用,来对相同的数据进行分组.在 SELECT 语句中,GROUP BY 子句放在 W ...
- [Java] 为什么要定义接口
摘自:https://www.douban.com/note/61810488/ 通俗的讲,就是为了降低耦合度. 一个很搞笑的例子: 看看下面的程序: 一个学校里边,有两种人:学生.老师.他们都要吃饭 ...
- Sql Server性能优化辅助指标SET STATISTICS TIME ON和SET STATISTICS IO ON
1.前言 对于优化SQL语句或存储过程,以前主要是用如下语句来判断具体执行时间,但是SQL环境是复杂多变的,下面语句并不能精准判断性能是否提高:如果需要精确知道CPU.IO等信息,就无能为力了. ), ...
- 【python】Python 字典(Dictionary)操作详解
Python字典是另一种可变容器模型,且可存储任意类型对象,如字符串.数字.元组等其他容器模型.一.创建字典字典由键和对应值成对组成.字典也被称作关联数组或哈希表.基本语法如下: dict = {'} ...