题目描述

  有一个 \(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. weblogic 安装配置打补丁

    Master Note on WebLogic Server (WLS) Patches, Upgrade Installers, and Full Installers

  2. pip 使用豆瓣源

    pip 使用豆瓣源 由于pip 默认使用Python的官方源pypi.python.org/pypi,导致我们经常使用pip装包时速度过慢或者无法安装(请求超时)等问题, 所以国内用户建议使用pip ...

  3. pthread_exit在main线程中的用处

    在main线程中调用pthread_exit会起到只让main线程退出,但是保留进程资源,供其他由main创建的线程使用,直至所有线程都结束,但在其他线程中不会有这种效果 https://stacko ...

  4. C++二分查找算法演示源码

    如下内容段是关于C++二分查找算法演示的内容. #include <cstdio>{ int l = 0, r = n-1; int mid; while (l <= r){ mid ...

  5. RN开发中的报错以及告警

    报错一: Attempted to transition from state `RESPONDER_INACTIVE_PRESS_IN` to `RESPONDER_ACTIVE_LONG_PRES ...

  6. Android .9.png 的介绍

    概述 .9.PNG是安卓开发里面的一种特殊的图片,这种格式的图片通过ADT自带的编辑工具生成,使用九宫格切分的方法.点九图是一种可拉伸的位图,android会自动调整它的大小,来使图像在充当背景时可以 ...

  7. android Q build 变化

    一 概述 android Q build变化整体上越来越严格,语法上之前能够使用的Q上将不能使用. 二 主要变化 2.1  'USER' 弃用 ‘USER’后面的值会被设置成‘nobody',andr ...

  8. Python简介之探观止矣

    Python是一门什么样的编程语言编程语言主要分为编译型和解释型,静态语言和动态语言,强类型和弱类型,混合语言等.编译型语言:通过编译器把源代码编译(compile)成机器语言,在经过链接(linke ...

  9. UITableView编辑模式大全解

    1.UITableView 的编辑模式 进入编辑模式 代码体现 // 设置 editing 属性 tableView?.editing = true // 这个设置的时候是有动画效果的 tableVi ...

  10. sizeof和strlen()区别及用法

    //sizeof是以字节为单位计算变量或类型所占内存大小,它是属于C语言运算符系列:而strlen()是一个函数,是计算字符串长度(也是以字节为单位,但略有区别):比如: char array[] = ...