BZOJ 4657: tower
来源:互联网 发布:dht网络 编辑:程序博客网 时间:2024/06/01 09:23
Description
Nick最近在玩一款很好玩的游戏,游戏规则是这样的:
有一个n*m的地图,地图上的每一个位置要么是空地,要么是炮塔,要么是一些BETA狗,Nick需要操纵炮塔攻击BETA狗们。
攻击方法是:对于每个炮塔,游戏系统已经给出它可以瞄准的方向(上下左右其中一个),Nick需要选择它的攻击位置,每一个炮塔只能够攻击一个位置,炮塔只能够向着它的瞄准方向上的某个位置发动攻击,当然炮塔也可以不进行攻击。炮塔威力强大,它可以且仅可以消灭目标位置上所有的BETA狗。
出于安全考虑,游戏系统已经保证不存在一个炮塔能够瞄准另外一个炮塔,即对于任意一个炮塔,它所有可能的攻击位置上不存在另外一个炮塔。而且,如果把炮塔的起点和终点称为炮弹的运行轨迹,那么系统不允许两条轨迹相交f包括起点和终点)。
现在,选定目标位置以后,每一个炮塔同时开炮,你要告诉Nick,他最多可以干掉多少BETA狗。
Input
第一行两个正整数n,m,表示地图的规模。
接下来礼行,每行m个整数,0表示空地,-1,-2,一3,-4分别表示瞄准上下左右的炮塔,若为正整数p,则表示该位置有p个BETA狗。
n,m <= 50,每个位置的BETA狗数量不超过999个,保证不存在任意一个炮塔能够瞄准另外一个炮塔
Output
一个正整数,表示Nick最多可以干掉几个BETA狗
Sample Input
3 2
0 9
-4 3
0 -1
Sample Output
9
分析
比赛的时候我根本没有想到网络流。。果然还是自己太弱了吗。。
而且这道题调了好久。。结果发现是数组开小了。。。
考虑最小割,我们可以先把每个炮台能打到的范围内的最大值找出来,加入答案。
考虑一个横着的炮塔和一个竖着的炮塔,他们有一个交点, 如果我们把一个炮塔到他要打的地方这一条路径中两两相邻的点连边,那么显然不能让两个炮塔之间有路径。
那么我们可以将每个点拆成两个点,一个表示横着走的点,称为横点;一个表示竖着走的点,称为竖点。每个点从竖点到横点连inf的边。
从s到每个竖着的炮台连inf的边,从每个横着的炮台到t连inf的边。
把每个竖着的炮台到其最大值的格子的路径上两两相邻的竖点连边,方向为炮塔打的方向,流量为最大值减去边的起点所在的格子的权值。也就是说若我们割了一条u->v的边,就相当于我们打u这个点(可以是自己)。
把每个横着的炮台到其最大值的格子的路径上两两相邻的横点连边,方向为炮塔的反方向,流量为最大值减去边的终点所在的格子的权值。也就是说若我们割了一条u->v的边,就相当于我们打v这个点。
那么由于s集和t集不能连通,所以这两个炮塔的路径上一定会有一条边被割掉。
于是我们用最大值的和减去最小割就是答案了。
代码
#include <bits/stdc++.h>#define N 55#define INF 0x7fffffffstruct NOTE{ int to,next,c;}e[N * N * 10];int cnt;int next[N * N * 2];int n,m;int ans;int minC;void add(int x,int y,int c){ e[++cnt].to = y; e[cnt].next = next[x]; e[cnt].c = c; next[x] = cnt; e[++cnt].to = x; e[cnt].next = next[y]; e[cnt].c = 0; next[y] = cnt;}int getId(int i,int j,int k){ if (k == 1) return (i - 1) * m + j; else return n * m + (i - 1) * m + j;}int s,t;int dis[N * N * 2];bool bfs(){ for (int i = s; i <= t; i++) dis[i] = 0; std::queue <int> Q; Q.push(s); dis[s] = 1; while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int i = next[u]; i; i = e[i].next) { if (e[i].c && !dis[e[i].to]) { dis[e[i].to] = dis[u] + 1; if (e[i].to == t) return 1; Q.push(e[i].to); } } } return 0;}int cur[N * N * 2];int dfs(int x,int maxf){ if (x == t || !maxf) return maxf; int ret = 0; for (int &i = cur[x]; i; i = e[i].next) if (e[i].c && dis[e[i].to] == dis[x] + 1) { int f = dfs(e[i].to,std::min(e[i].c,maxf - ret)); ret += f; e[i].c -= f; e[i ^ 1].c += f; if (ret == maxf) break; } return ret;}void dinic(){ while (bfs()) { for (int i = s; i <= t; i++) cur[i] = next[i]; minC += dfs(s,INF); }}int mp[N][N];void cd(int i,int j){ add(getId(i,j,1),getId(i,j,2),INF);}void lt(int i,int j){ if (mp[i][j] >= -2) { add(s,getId(i,j,1),INF); if (mp[i][j] == -1) { int mx = 0; for (int k = i - 1; k; k--) mx = std::max(mp[k][j],mx); for (int k = i - 1; k; k--) add(getId(k + 1,j,1),getId(k,j,1),mx - std::max(mp[k + 1][j],0)); ans += mx; } else { int mx = 0; for (int k = i + 1; k <= n; k++) mx = std::max(mp[k][j],mx); for (int k = i + 1; k <= n; k++) add(getId(k - 1,j,1),getId(k,j,1),mx - std::max(mp[k - 1][j],0)); ans += mx; } } else { add(getId(i,j,2),t,INF); if (mp[i][j] == -3) { int mx = 0; for (int k = 1; k < j; k++) mx = std::max(mx,mp[i][k]); for (int k = 1; k < j; k++) add(getId(i,k,2),getId(i,k + 1,2),mx - std::max(mp[i][k + 1],0)); ans += mx; } else { int mx = 0; for (int k = m; k > j; k--) mx = std::max(mx,mp[i][k]); for (int k = m; k > j; k--) add(getId(i,k,2),getId(i,k - 1,2),mx - std::max(mp[i][k - 1],0)); ans += mx; } }}int main(){ freopen("tower.in","r",stdin); freopen("tower.out","w",stdout); scanf("%d%d",&n,&m); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d",&mp[i][j]); s = 0; t = 2 * n * m + 1; cnt = 1; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) if (mp[i][j] >= 0) cd(i,j); else lt(i,j); dinic(); printf("%d\n",ans - minC);}
- BZOJ 4657: tower
- bzoj 4657: tower 最小割
- bzoj 4352 tower
- BZOJ 4352: Tower|暴力
- BZOJ 1233: [Usaco2009Open]干草堆tower
- BZOJ 1233: [Usaco2009Open]干草堆tower
- BZOJ 1233 [Usaco2009Open]干草堆tower
- 4657: tower
- BZOJ 1233: [Usaco2009Open]干草堆tower|动态规划
- [BZOJ 1233][Usaco2009Open]干草堆tower:单调队列
- Tower
- tower
- Ivory Tower
- hdu2971 Tower
- [DP]Tower
- 【计数】tower
- hannuo tower
- Hanoi Tower
- 系统命令执行中MySQL修改数据表
- Algorithm Gossip (7) 骑士走棋盘(Knight tour)
- Android状态栏颜色修改
- MVC中HtmlHelper用法大全参考
- 每天一个Linux命令(42):free
- BZOJ 4657: tower
- 前台开发总结04——2017.04.13
- 我的笔记 FlowLayout 流式布局管理器
- ssh免密码登录(Ubuntu16.04版本)亲测可用,网上说的10个有9个搞不出来
- 546. Remove Boxes
- 论文笔记 Bootstrapping Face Detection with Hard Negative Examples
- 如何从Eclipse导入github上的项目源码
- 一致性HASH算法
- 在HTML中用iframe标签引入另一个页面