题目描述

  有一个 \(n\times m\)的网格,每个格子里面可能有一些炮塔,或者有几个人。

  每个炮塔可以在给定的方向(上下左右)上选一个点作为它的攻击位置,然后消灭这个格子里面的所有人。当然也可以不进行攻击。

  要求两个炮弹的飞行轨迹不能相交。

  问你最多能打死多少个人。

  保证不存在一个炮塔可以攻击另一个炮塔的情况。

  \(n,m\leq 50,\) 每个格子的人数 \(< 1000\)

题解

  先忽略"要求两个炮弹的飞行轨迹不能相交"这个条件。

  那么可以把每个炮塔能攻击到的格子找出来,连成一条链,容量为前面这个格子的人数。

  但这样求出来的是最小值。

  用一个大整数去减掉每个数作为边权就好了。

  现在有"要求两个炮弹的飞行轨迹不能相交"这个条件。

  参考 HNOI2013这道题。

  可以把朝向为左右的炮塔的链的方向反过来,然后在相交的位置上连一条(竖着的炮塔那一列对应的格子 \(\to\) 横着的炮塔那一行对应的格子)的边,容量为 \(\infty\)。

  为什么这是对的?

  

  如果竖着的炮塔攻击的点超过了两条链的交点,横着的炮塔攻击的点也超过了两条链的交点,那么那条容量为 \(\infty\) 的边就一定会有流量经过,然后会沿着 \(S\to\) 交点 \(\to T\) 流到终点。所以这样建图就保证了如果竖着的炮塔攻击的点超过了两条链的交点,那么横着的炮塔攻击的点就不会超过了两条链的交点。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
if(a>b)
swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
int rd()
{
int s=0,c,b=0;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c=='-')
{
c=getchar();
b=1;
}
do
{
s=s*10+c-'0';
}
while((c=getchar())>='0'&&c<='9');
return b?-s:s;
}
void put(int x)
{
if(!x)
{
putchar('0');
return;
}
static int c[20];
int t=0;
while(x)
{
c[++t]=x%10;
x/=10;
}
while(t)
putchar(c[t--]+'0');
}
int upmin(int &a,int b)
{
if(b<a)
{
a=b;
return 1;
}
return 0;
}
int upmax(int &a,int b)
{
if(b>a)
{
a=b;
return 1;
}
return 0;
}
const int inf=0x7fffffff;
namespace flow
{
int v[100010];
int c[100010];
int t[100010];
int h[100010];
int cnt;
void add(int x,int y,int a)
{
cnt++;
v[cnt]=y;
c[cnt]=a;
t[cnt]=h[x];
h[x]=cnt;
}
int e[100010];
int d[100010];
int op(int x)
{
return ((x-1)^1)+1;
}
int S,T,num;
queue<int> q;
void bfs()
{
memset(d,-1,sizeof d);
q.push(T);
d[T]=0;
while(!q.empty())
{
int x=q.front();
q.pop();
e[d[x]]++;
for(int i=h[x];i;i=t[i])
if(c[op(i)]&&d[v[i]]==-1)
{
d[v[i]]=d[x]+1;
q.push(v[i]);
}
}
}
int cur[100010];
int dfs(int x,int flow)
{
if(x==T)
return flow;
int s=0;
for(int &i=cur[x];i;i=t[i])
if(c[i]&&d[v[i]]==d[x]-1)
{
int u=dfs(v[i],min(flow,c[i]));
c[i]-=u;
c[op(i)]+=u;
flow-=u;
s+=u;
if(!flow)
return s;
}
e[d[x]]--;
if(!e[d[x]])
e[S]=num;
d[x]++;
e[d[x]]++;
cur[x]=h[x];
return s;
}
int solve()
{
bfs();
int ans=0;
memcpy(cur,h,sizeof h);
while(d[S]>=0&&d[S]<=num-1)
ans+=dfs(S,inf);
return ans;
}
}
void add(int x,int y,int z)
{
flow::add(x,y,z);
flow::add(y,x,0);
}
int n,m;
int a[100][100];
int b[100][100];
int main()
{
open("c");
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
flow::S=1;
flow::T=2;
flow::num=2;
int cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]==-3)
{
if(j==1)
continue;
cnt++;
for(int k=j;k>=1;k--)
b[i][k]=++flow::num;
add(flow::S,b[i][1],1000-a[i][1]);
for(int k=1;k<j;k++)
add(b[i][k],b[i][k+1],1000-a[i][k+1]);
add(b[i][j],flow::T,1000);
}
else if(a[i][j]==-4)
{
if(j==m)
continue;
cnt++;
for(int k=j;k<=m;k++)
b[i][k]=++flow::num;
add(flow::S,b[i][m],1000-a[i][m]);
for(int k=j;k<m;k++)
add(b[i][k+1],b[i][k],1000-a[i][k]);
add(b[i][j],flow::T,1000);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]==-1)
{
if(i==1)
continue;
cnt++;
for(int k=1;k<=i;k++)
{
int v=++flow::num;
if(b[k][j])
add(v,b[k][j],inf);
b[k][j]=v;
}
add(flow::S,b[i][j],1000);
add(b[i][j],b[i-1][j],1000);
for(int k=i-1;k>1;k--)
add(b[k][j],b[k-1][j],1000-a[k][j]);
add(b[1][j],flow::T,1000-a[1][j]);
}
else if(a[i][j]==-2)
{
if(i==n)
continue;
cnt++;
for(int k=i;k<=n;k++)
{
int v=++flow::num;
if(b[k][j])
add(v,b[k][j],inf);
b[k][j]=v;
}
add(flow::S,b[i][j],1000);
add(b[i][j],b[i+1][j],1000);
for(int k=i+1;k<n;k++)
add(b[k][j],b[k+1][j],1000-a[k][j]);
add(b[n][j],flow::T,1000-a[n][j]);
}
int ans=flow::solve();
ans=cnt*1000-ans;
printf("%d\n",ans);
return 0;
}

【XSY2925】cti 网络流的更多相关文章

  1. JZOJ 5602.【NOI2018模拟3.26】Cti

    JZOJ 5602.[NOI2018模拟3.26]Cti Description 有一个 \(n×m\) 的地图,地图上的每一个位置可以是空地,炮塔或是敌人.你需要操纵炮塔消灭敌人. 对于每个炮塔都有 ...

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

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

  3. 网络流模板 NetworkFlow

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

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

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

  5. ACM/ICPC 之 有流量上下界的网络流-Dinic(可做模板)(POJ2396)

    //有流量上下界的网络流 //Time:47Ms Memory:1788K #include<iostream> #include<cstring> #include<c ...

  6. BZOJ 3144 [Hnoi2013]切糕 ——网络流

    [题目分析] 网络流好题! 从割的方面来考虑问题往往会得到简化. 当割掉i,j,k时,必定附近的要割在k-D到k+D上. 所以只需要建两条inf的边来强制,如果割不掉强制范围内的时候,原来的边一定会换 ...

  7. bzoj3572又TM是网络流

    = =我承认我写网络流写疯了 = =我承认前面几篇博文都是扯淡,我写的是垃圾dinic(根本不叫dinic) = =我承认这道题我调了半天 = =我承认我这道题一开始是T的,后来换上真正的dinic才 ...

  8. hdu3549还是网络流

    最后一次训练模板(比较熟练了) 接下来训练网络流的建图 #include <cstdio> #define INF 2147483647 int n,m,ans,x,y,z,M,h,t,T ...

  9. 二分图&网络流&最小割等问题的总结

    二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 技巧: 1.拆点为边,即一个点有限制,可将其转化为边 BZOJ1066, ...

随机推荐

  1. iOS----------常见宏定义

    在我们日常的项目中,合理的使用宏定义,会大大减少我们的代码量,以及代码的可读性,为方便读者使用,总结如下: pragma mark - Application相关 ///=============== ...

  2. linux初学者常用必备命令整理

    Linux命令学习 1.文件&目录处理 ls -a 全部文件 -l 详细信息 -r 递归显示子目录结构 ls -al 相当于 ls -a -l cd ..上级目录 .当前目录 ~家目录 cd ...

  3. MongoDB:数据库介绍与基础操作

    二.部署在本地服务器 在上次的学习过程中,我们主要进行了MongoDB运行环境的搭建和可视化工具的安装.此次我们将学习MongoDB有关的基本概念和在adminmongo上的基本操作.该文档中的数据库 ...

  4. Sql Server 获取本周周一

    SELECT DATEADD(Day,(@i+1)-(DATEPART(Weekday,getdate())+@@DATEFIRST-1)%7,getdate())

  5. python粗谈面向对象(一)

    1.面向过程编程vs函数式编程 面向过程编程 以计算对象的元素个数为例. str_1 = 'abcdefg' count = 0 for i in str_1: # 统计字符串元素个数 count + ...

  6. 【原】Java学习笔记004 - 运算符

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 运算符:对常量 或 ...

  7. Asp.Net Core 下 Newtonsoft.Json 转换字符串 null 替换成string.Empty

    public class NullToEmptyStringResolver : DefaultContractResolver { /// <summary> /// 创建属性 /// ...

  8. Python基础——3特性

    特性 切片 L=[0,1,2,3,4,5,6,7,8,9,10] L[:3]=[0,1,2] L[-2:]=[9,10] L[1:3]=[1,2] L[::3]=[0,3,6,9] L[:5:2]=[ ...

  9. 前端面试回顾---javascript的面向对象

    转:https://segmentfault.com/a/1190000011061136 前言 前一阵面试,过程中发现问到一些很基础的问题时候,自己并不能很流畅的回答出来.或者遇到一些基础知识的应用 ...

  10. Ajax概述和判断用户名是否存在的简单代码练习

    在本代码中主要体现,Ajax实现了部分位置的刷新.不需要重新刷新网页,重新请求服务器.下面用过代码来对Ajax更深的认识 这里需要创建,一个jsp文件(显示登录界面),js文件(对Ajax的主要设置) ...