Problem Statement

There is a grid with $H$ rows from top to bottom and $W$ columns from left to right. Let $(i, j)$ denote the square at the $i$-th row from the top and $j$-th column from the left.

Square $(i, j)$ is occupied by an obstacle if $S_{i,j}=$ #, and is empty if $S_{i,j}=$ ..

Takahashi will install some surveillance cameras in the grid.

A surveillance camera can be placed at a square without an obstacle, in one of the four directions: up, down, left, or right.

Multiple surveillance cameras may be placed at the same square.

Each surveillance camera monitors the square it is placed at, and the squares in the direction it is placed in, as far as there is no obstacle in between.

At least how many surveillance cameras are needed to monitor all squares without an obstacle?

Constraints

  • $1 \leq H,W \leq 300$
  • $S_{i,j}$ is . or #.

Input

The input is given from Standard Input in the following format:

$H$ $W$
$S_{1,1}\ldots S_{1,W}$
$\vdots$
$S_{H,1}\ldots S_{H,W}$

Output

Print the answer.


Sample Input 1

3 3
...
.#.
...

Sample Output 1

4

For example, if we install two surveillance cameras at square $(1, 1)$ facing right and down, and another two at square $(3, 3)$ facing up and left, all squares without an obstacle will be monitored.


Sample Input 2

3 5
...##
.#...
...#.

Sample Output 2

5

For example, if we install two surveillance cameras at square $(1, 1)$ facing right and down, another at square $(3, 3)$ facing left, and another two at square $(2, 5)$ facing left and down, all squares without an obstacle will be monitored.

Note that the camera at square $(2, 5)$ facing left cannot monitor square $(2, 1)$, since there is an obstacle in between at square $(2, 2)$.


Sample Input 3

14 107
...........................................................................................................
...........................................................................................................
..#########..###....###########..###.......###...###########..####.......###...###########...###########...
..########..###....###########....###.....###...###########...#####......###..###########...###########....
..#######..###.....###.............###...###....###...........######.....###..###...........###............
..######..###......###..............###.###.....###...........###.###....###..###...........###............
..#####..###.......############......#####......############..###..###...###..###...........############...
..####....###......############.......###.......############..###...###..###..###...........############...
..###......###.....###................###.......###...........###....###.###..###...........###............
..##........###....###................###.......###...........###.....######..###...........###............
..#..........###...############.......###.......############..###......#####..############..############...
..............###...###########.......###........###########..###.......####...###########...###########...
...........................................................................................................
...........................................................................................................

Sample Output 3

91

最优化问题,在尝试了贪心,dp后,走向网络流。

首先一个监控有4个方向,但是只有两个方向有用。因为你在一个地方放置向右的监控,效果一定不差于在这个地方往右遇到的第一个障碍的前面或边界放置一个往左的监控。之后不妨设只有向下和向右的两种方向的监控。

另一个结论是,一个点会放向下的监控,当且仅当他位于上边界或者他上面是障碍,不然他的效果1肯定不如再往上一格去放。向右的监控同理。

最大流很难建图,考虑去求最小割。不妨把一个点拆成两个点,一个代表他是否放置往右的监控,一个代表他是否放置往下的监控。源点连向每一个代表是否放置往右监控的店,每一个代表是否放置往下的监控的点连向汇点,流量均为1。对于一个点,处理出他往上最近的一个可以放置的店,他往左最近的一个可以放置的店。这两个点至少要选一个,所以给这两个点分别代表的点中间连一条流量为正无穷的边。那么此时跑最大流,一条边断了,表示他放置往下/往右的监控。那么此时每个点代表的每条边,他的左右都至少1有一个点选了,也就代表这个点被覆盖了。

发现图是二分图,复杂度 \(O((HW)^{1.5})\)

#include<bits/stdc++.h>
using namespace std;
const int N=305,M=3*N*N+6;
int h,w,e_num(1),hd[M],s,t,l,r,q[M],v[M],k,vhd[M],x[N][N],y[N][N],ans;
struct edge{
int v,nxt,f;
}e[N*N*10];
int get(int x,int y)
{
return x*h+w;
}
void add_edge(int u,int v,int f)
{
// printf("%d %d %d\n",u,v,f);
e[++e_num]=(edge){v,hd[u],f};
hd[u]=e_num;
}
char str[N][N];
int bfs()
{
memset(v,0,sizeof(v));
q[l=r=1]=s,v[s]=1;
memcpy(hd,vhd,sizeof(hd));
while(l<=r)
{
for(int i=hd[q[l]];i;i=e[i].nxt)
{
if(!v[e[i].v]&&e[i].f)
{
// printf("%d %d %d\n",q[l],e[i].v,e[i].f);
v[e[i].v]=v[q[l]]+1;
q[++r]=e[i].v;
}
}
++l;
}
// for(int i=1;i<=t;i++)
// printf("%d ",v[i]);
// putchar('\n');
return v[t];
}
int dfs(int x,int flow)
{
if(x==t)
return flow;
int s=0;
for(int&i=hd[x];i;i=e[i].nxt)
{
if(v[e[i].v]==v[x]+1&&e[i].f)
{
int t=dfs(e[i].v,min(flow,e[i].f));
flow-=t,s+=t;
e[i].f-=t,e[i^1].f+=t;
if(!t)
v[e[i].v]=0;
if(!flow)
break;
}
}
return s;
}
int main()
{
scanf("%d%d",&h,&w) ;
s=2*h*w,t=2*h*w+1;
for(int i=0;i<h;i++)
scanf("%s",str[i]);
for(int i=0;i<h;i++)
{
for(int j=0;j<w;j++)
{
if(str[i][j]=='#')
continue;
k=i*w+j;
if(!i||str[i-1][j]=='#')
{
x[i][j]=k;
add_edge(s,k,1);
add_edge(k,s,0) ;
}
else
x[i][j]=x[i-1][j];
if(!j||str[i][j-1]=='#')
{
y[i][j]=k;
add_edge(k+h*w,t,1);
add_edge(t,k+h*w,0);
}
else
y[i][j]=y[i][j-1];
add_edge(x[i][j],y[i][j]+h*w,1e9);
add_edge(y[i][j]+h*w,x[i][j],0);
}
}
memcpy(vhd,hd,sizeof(hd));
while(bfs())
while(k=dfs(s,2e9))
ans+=k;
printf("%d",ans);
}

[ABC274G] Security Camera 3的更多相关文章

  1. ABC220H - Security Camera

    考虑折半,将点按照标号是否 \(\le \frac{n}{2}\) 分成两个集合 \(S_1, S_2\). 首先原问题的形式有点奇怪,我们不妨统计没有被覆盖覆盖的边为偶数条的情况. 这样一来问题转化 ...

  2. Unity3D重要知识点

    数据结构和算法很重要!图形学也很重要!大的游戏公司很看重个人基础,综合能力小公司看你实际工作能力,看你的Demo. 1.什么是渲染管道? 是指在显示器上为了显示出图像而经过的一系列必要操作. 渲染管道 ...

  3. Unity3D 面试题汇总

    最先执行的方法是: 1.(激活时的初始化代码)Awake,2.Start.3.Update[FixUpdate.LateUpdate].4.(渲染模块)OnGUI.5.再向后,就是卸载模块(TearD ...

  4. Unity随机随学

    1.什么是渲染管道? 是指在显示器上为了显示出图像而经过的一系列必要操作.渲染管道中的步骤很多,都要将几何物体从一个坐标系中变换到另一个坐标系中去. 主要步骤有: 本地坐标->视图坐标-> ...

  5. 越狱Season 1-Episode 15: By the Skin and the Teeth

    Season 1, Episode 15: By the Skin and the Teeth -Pope: doctor...you can leave. 医生你得离开 -Burrows: It's ...

  6. U3D常用题

    最先执行的方法是:1.(激活时的初始化代码)Awake,2.Start.3.Update[FixUpdate.LateUpdate].4.(渲染模块)OnGUI.5.再向后,就是卸载模块(TearDo ...

  7. Questions about UIUC and USC

    Questions about UIUC and USC I am admitted to University of Illinois at Urbana-Champaign (UIUC) Prof ...

  8. Unity3D 面试ABC

    最先执行的方法是: 1.(激活时的初始化代码)Awake,2.Start.3.Update[FixUpdate.LateUpdate].4.(渲染模块)OnGUI.5.再向后,就是卸载模块(TearD ...

  9. U3D 基础

    千里之行,始于足下! 最先执行的方法是:1.(激活时的初始代码)Awake2.Start3.Update(FixUpdate,LateUpdate)4.渲染模块(OnGUI)5.再向后,就是卸载模块( ...

  10. Unity3d笔试题大全

    1.       [C#语言基础]请简述拆箱和装箱. 答: 装箱操作: 值类型隐式转换为object类型或由此值类型实现的任何接口类型的过程. 1.在堆中开辟内存空间. 2.将值类型的数据复制到堆中. ...

随机推荐

  1. ES集群&kibana安装

    一.elasticsearch介绍 Elasticsearch 是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful 风格接口,多数据源,自动搜索负 ...

  2. 《Python魔法大冒险》009 魔法之语:字符串的奥秘

    随着小鱼和魔法师的深入,他们来到了一个被薄雾笼罩的湖泊.湖中央有一个小岛,岛上有一棵巨大的古树,树上挂满了闪闪发光的果实,每一个果实上都刻着一个字母或符号. 小鱼好奇地问:"这些是什么果实? ...

  3. 小知识:PPT的幻灯片放映设置

    最近给某客户讲课时,碰到了幻灯片自动翻页的情况,发现是因为之前做过粗略的计时演练,有些片子就快速过了. 问题现象: 结果导致放映时也出现了某些片子快速被自动翻页. 解决方案: 设置成手动推进幻灯片的方 ...

  4. modbus转profinet网关连接ABB变频器在博图程序案例

    modbus转profinet网关连接ABB变频器在博图程序案例 在博图里PLC无需编程利用兴达易控modbus转Profinet网关将ABB变频器接入到西门子网络中,用到设备为西门子1200PLC, ...

  5. Python基础——函数的理解、函数对象、函数嵌套、闭包函数、及其应用

    文章目录 函数也是变量 可以赋值 可以当做函数当做参数传给另外一个函数 可以当做函数当做另外一个函数的返回值 可以当做容器类型的一个元素 函数对象应用示范 原始版 修正版 函数嵌套 函数的嵌套调用 函 ...

  6. This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.

    This TensorFlow binary is optimized to use available CPU instructions in performance-critical operat ...

  7. .netCore 图形验证码,非System.Drawing.Common

    netcore需要跨平台,说白点就是放在windows服务器要能用,放在linux服务器上也能用,甚至macos上. 很多时候需要使用到图形验证码,这就有问题了. 旧方案1.引入包 <Packa ...

  8. 【学习】fhq-treap

    fhq-treap 是一种好写.复杂度低,且功能的优秀数据结构,涵盖了 treap 几乎所有的功能,其巧妙之处,就在于运用分离和合并两种操作代替了旋转操作. 1. BST 的定义 (摘自 OI Wik ...

  9. mysql学习之数据备份和恢复

    一.使用mysqldump进行备份 如:将test数据库备份到/tmp/mysql_back/目录下 [root@localhost tmp]# mysqldump -uroot -p111 -l - ...

  10. 关于Windows打印机驱动相关问题-如何利用Java(或其他)调用打印机驱动程序完成原始文件翻译为PCL语言的步骤

    前面这些都是问题描述,问题在偏下面 场景:用户电脑上安装了PCL驱动,可通过驱动完成打印. 需求:现在需要提供一种脱离PC端完成文件上传并打印的功能.让用户使用手机或pc未安装驱动时都能打印文件. 目 ...