HDU 2732:Leapin' Lizards(最大流)
http://acm.hdu.edu.cn/showproblem.php?pid=2732
题意:给出两个地图,蜥蜴从一个柱子跳跃到另外一个地方,那么这个柱子就可能会坍塌,第一个地图是柱子可以容忍跳跃多少次(即从它为起点可以跳跃多少次,然后坍塌),第二个地图是蜥蜴的位置。还有一个跳跃距离d,即蜥蜴可以跳跃不超过d的距离(曼哈顿距离),如果跳到地图外面,即蜥蜴逃跑成功,问最终留下的蜥蜴数最少是多少。
思路:我觉得如果不是在做网络流套题应该想不到这是网络流。其实挺简单的建图。首先考虑蜥蜴的位置,和柱子的位置,如果柱子的位置有蜥蜴,那么这个柱子可以容忍的跳跃次数wi要-1,因为这个地方的蜥蜴必须跳走。然后把蜥蜴的位置,柱子的位置,和地图外边的位置存下来,蜥蜴和柱子拆点,形成一个S->lizard1->lizard2->pil1->pil2->out->T这样的网络。
1、如果蜥蜴可以直接跳到地图外,那么可以在lizard2和out之间连一条边,如果柱子可以跳到地图外,就在pil2和out之间连边,权值都为INF。
2、如果柱子之间如果距离在d之间,那么也可以连边,权值为将要跳到的柱子的wi。
3、如果蜥蜴可以跳到柱子,那么可以连边,权值为柱子的wi。
4、S和lizard1连边权值为1。
5、out和T连边权值为INF。
6、蜥蜴拆点权值为1,柱子拆点权值为wi。
这样就做完了。注意输出要仔细。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
typedef long long LL;
struct Edge {
int v, nxt, cap;
Edge () {}
Edge (int v, int cap, int nxt) : v(v), cap(cap), nxt(nxt) {}
} edge[N];
struct Node {
int x, y;
friend bool operator < (const Node &a, const Node &b) {
return a.x < b.x;
}
} lizard[N], pil[N], out[N];
int head[N], tot, cur[N], gap[N], pre[N], dis[N], w[N], S, T; void Add(int u, int v, int cap) {
edge[tot] = Edge(v, cap, head[u]); head[u] = tot++;
edge[tot] = Edge(u, , head[v]); head[v] = tot++;
} int Cal(Node a, Node b) {
return abs(a.x - b.x) + abs(a.y - b.y);
} void BFS() {
memset(dis, -, sizeof(dis));
memset(gap, , sizeof(gap));
queue<int> que; que.push(T);
dis[T] = ; gap[]++;
while(!que.empty()) {
int u = que.front(); que.pop();
for(int i = head[u]; ~i; i = edge[i].nxt) {
Edge& e = edge[i];
if(~dis[e.v]) continue;
dis[e.v] = dis[u] + ;
que.push(e.v);
gap[dis[e.v]]++;
}
}
} int ISAP(int n) {
BFS();
memcpy(cur, head, sizeof(cur));
int ans = , i, u = pre[S] = S;
while(dis[S] < n) {
if(u == T) {
int flow = INF, index;
for(i = S; i != T; i = edge[cur[i]].v)
if(edge[cur[i]].cap < flow) flow = edge[cur[i]].cap, index = i;
for(i = S; i != T; i = edge[cur[i]].v)
edge[cur[i]].cap -= flow, edge[cur[i]^].cap += flow;
ans += flow; u = index;
}
for(i = cur[u]; ~i; i = edge[i].nxt)
if(dis[edge[i].v] + == dis[u] && edge[i].cap > ) break;
if(~i) {
pre[edge[i].v] = u; cur[u] = i;
u = edge[i].v;
} else {
if(--gap[dis[u]] == ) break;
int md = n;
for(int i = head[u]; ~i; i = edge[i].nxt)
if(dis[edge[i].v] < md && edge[i].cap > )
md = dis[edge[i].v], cur[u] = i;
gap[dis[u] = md + ]++;
u = pre[u];
}
}
return ans;
} int main() {
int t, cas = ;
cin >> t;
while(t--) {
int n, d, m; char mp[][], s[][];
scanf("%d%d", &n, &d);
memset(head, -, sizeof(head)); tot = ;
int lzcnt = , picnt = , oucnt = ;
for(int i = ; i <= n; i++) scanf("%*c%s", mp[i] + );
m = strlen(mp[] + );
for(int i = ; i <= n; i++) {
scanf("%*c%s", s[i] + );
for(int j = ; j <= m; j++) {
if(s[i][j] == 'L') {
lizard[++lzcnt].x = i, lizard[lzcnt].y = j;
if(mp[i][j] - '' > ) {
pil[++picnt].x = i, pil[picnt].y = j, w[picnt] = mp[i][j] - '' - ; // 如果柱子位置有蜥蜴,那么流量要-1
}
} else if(mp[i][j] != '') {
pil[++picnt].x = i, pil[picnt].y = j, w[picnt] = mp[i][j] - '';
}
}
}
for(int i = ; i <= n; i++) {
out[++oucnt].x = i; out[oucnt].y = ;
out[++oucnt].x = i; out[oucnt].y = m + ;
}
for(int i = ; i <= m; i++) {
out[++oucnt].x = ; out[oucnt].y = i;
out[++oucnt].x = n + ; out[oucnt].y = i;
}
S = ; T = * lzcnt + * picnt + oucnt + ;
for(int i = ; i <= lzcnt; i++) Add(S, i, ), Add(i, i + lzcnt, ); // 源点和蜥蜴,蜥蜴拆点
for(int i = ; i <= oucnt; i++) Add( * lzcnt + * picnt + i, T, INF); // 边界点和汇点
for(int i = ; i <= picnt; i++) Add( * lzcnt + i, * lzcnt + picnt + i, w[i]); // 跳跃点拆点
for(int i = ; i <= lzcnt; i++) {
for(int j = ; j <= picnt; j++) {
if(Cal(lizard[i], pil[j]) <= d && Cal(lizard[i], pil[j]) != ) {
Add(i + lzcnt, j + * lzcnt, w[j]); // 蜥蜴的第二个点和跳跃点第一个点
}
}
for(int j = ; j <= oucnt; j++) {
if(Cal(lizard[i], out[j]) <= d) Add(i + lzcnt, j + lzcnt * + picnt * , INF);
}
}
for(int i = ; i <= picnt; i++) {
for(int j = i + ; j <= picnt; j++) {
if(Cal(pil[i], pil[j]) <= d) {
Add(i + * lzcnt + picnt, j + * lzcnt, INF); // 跳跃点
Add(j + * lzcnt + picnt, i + * lzcnt, INF);
}
}
for(int j = ; j <= oucnt; j++) {
if(Cal(pil[i], out[j]) <= d) Add(i + lzcnt * + picnt, j + lzcnt * + picnt * , INF);
}
}
int ans = lzcnt - ISAP(T + );
printf("Case #%d: ", ++cas);
if(ans < ) {
if(ans <= ) printf("no lizard was ");
else printf("1 lizard was ");
} else {
printf("%d lizards were ", ans);
}
puts("left behind.");
}
return ;
}
#看了一下别人的思路,一开始自己也想的差不多那样,但是硬是调不出来,就用了这么复杂方法,觉得自己没救了,好简单的思路。
S->pil1->pil2->T,如果柱子上有蜥蜴就将这个点和S连,如果在该柱子可以跳出去,那么就将这个点和T相连,然后和能够相连的柱子连边就好了。再写一遍
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
typedef long long LL;
struct Edge {
int v, nxt, cap;
Edge () {}
Edge (int v, int cap, int nxt) : v(v), cap(cap), nxt(nxt) {}
} edge[N];
struct Node {
int x, y, w, flag;
} pil[N];
int head[N], tot, cur[N], gap[N], pre[N], dis[N], S, T; void Add(int u, int v, int cap) {
edge[tot] = Edge(v, cap, head[u]); head[u] = tot++;
edge[tot] = Edge(u, , head[v]); head[v] = tot++;
} int Cal(Node a, Node b) {
return abs(a.x - b.x) + abs(a.y - b.y);
} void BFS() {
memset(dis, -, sizeof(dis));
memset(gap, , sizeof(gap));
queue<int> que; que.push(T);
dis[T] = ; gap[]++;
while(!que.empty()) {
int u = que.front(); que.pop();
for(int i = head[u]; ~i; i = edge[i].nxt) {
Edge& e = edge[i];
if(~dis[e.v]) continue;
dis[e.v] = dis[u] + ;
que.push(e.v);
gap[dis[e.v]]++;
}
}
} int ISAP(int n) {
BFS();
memcpy(cur, head, sizeof(cur));
int ans = , i, u = pre[S] = S;
while(dis[S] < n) {
if(u == T) {
int flow = INF, index;
for(i = S; i != T; i = edge[cur[i]].v)
if(edge[cur[i]].cap < flow) flow = edge[cur[i]].cap, index = i;
for(i = S; i != T; i = edge[cur[i]].v)
edge[cur[i]].cap -= flow, edge[cur[i]^].cap += flow;
ans += flow; u = index;
}
for(i = cur[u]; ~i; i = edge[i].nxt)
if(dis[edge[i].v] + == dis[u] && edge[i].cap > ) break;
if(~i) {
pre[edge[i].v] = u; cur[u] = i;
u = edge[i].v;
} else {
if(--gap[dis[u]] == ) break;
int md = n;
for(int i = head[u]; ~i; i = edge[i].nxt)
if(dis[edge[i].v] < md && edge[i].cap > )
md = dis[edge[i].v], cur[u] = i;
gap[dis[u] = md + ]++;
u = pre[u];
}
}
return ans;
} int main() {
int t, cas = ;
cin >> t;
while(t--) {
int n, d, m; char mp[][], s[][];
scanf("%d%d", &n, &d);
memset(head, -, sizeof(head)); tot = ;
int cnt = , tol = ;
for(int i = ; i <= n; i++) {
scanf("%s", s[i] + );
m = strlen(s[i] + );
for(int j = ; j <= m; j++)
if(s[i][j] != '') pil[++cnt].x = i, pil[cnt].y = j, pil[cnt].w = s[i][j] - '';
}
for(int i = ; i <= n; i++) {
scanf("%s", mp[i] + );
for(int j = ; j <= m; j++) {
for(int k = ; k <= cnt; k++) {
if(pil[k].x == i && pil[k].y == j) {
if(mp[i][j] == 'L') pil[k].flag = , tol++;
else pil[k].flag = ;
break;
}
}
}
}
S = , T = * cnt + ;
for(int i = ; i <= cnt; i++) {
Add(i, i + cnt, pil[i].w);
if(pil[i].flag == ) Add(S, i, );
for(int j = i + ; j <= cnt; j++) {
if(Cal(pil[i], pil[j]) <= d) {
Add(i + cnt, j, INF);
Add(j + cnt, i, INF);
}
}
if(pil[i].x <= d || pil[i].y <= d || n - pil[i].x < d || m - pil[i].y < d)
Add(i + cnt, T, INF);
} int ans = tol - ISAP(T + );
printf("Case #%d: ", ++cas);
if(ans < ) {
if(ans <= ) printf("no lizard was ");
else printf("1 lizard was ");
} else {
printf("%d lizards were ", ans);
}
puts("left behind.");
}
return ;
}
HDU 2732:Leapin' Lizards(最大流)的更多相关文章
- hdu 2732 Leapin' Lizards 最大流 拆点 建图
题目链接 题意 给定一张网格,格子中有些地方有柱子,有些柱子上面有蜥蜴. 每个柱子只能承受有限只蜥蜴从上面经过.每只蜥蜴每次能走到相距曼哈顿距离\(\leq k\)的格子中去. 问有多少只蜥蜴能走出网 ...
- hdu 2732 Leapin' Lizards (最大流 拆点建图)
Problem Description Your platoon of wandering lizards has entered a strange room in the labyrinth yo ...
- POJ 2711 Leapin' Lizards / HDU 2732 Leapin' Lizards / BZOJ 1066 [SCOI2007]蜥蜴(网络流,最大流)
POJ 2711 Leapin' Lizards / HDU 2732 Leapin' Lizards / BZOJ 1066 [SCOI2007]蜥蜴(网络流,最大流) Description Yo ...
- HDU 2732 Leapin' Lizards(最大流)
http://acm.hdu.edu.cn/showproblem.php?pid=2732 题意: 给出n行的网格,还有若干只蜥蜴,每只蜥蜴一开始就在一个格子之中,并且给出蜥蜴每次的最大跳跃长度d. ...
- hdu 2732 Leapin' Lizards(最大流)Mid-Central USA 2005
废话: 这道题不难,稍微构造一下图就可以套最大流的模板了.但是我还是花了好久才解决.一方面是最近确实非常没状态(托词,其实就是最近特别颓废,整天玩游戏看小说,没法静下心来学习),另一方面是不够细心,输 ...
- HDU - 2732 Leapin' Lizards (拆点最大流)
题意:有N*M的矩形,每个格点有一个柱子,每根柱子有高度c,允许蜥蜴经过这根柱子c次,开始有一些蜥蜴在某些柱子上,它们要跳出这个矩形,每步最大能跳d个单位,求最少有多少蜥蜴不能跳出这个矩形. 分析:转 ...
- HDU 2732 Leapin' Lizards
网络最大流+拆点.输出有坑!!! #include<cstdio> #include<cstring> #include<string> #include<c ...
- HDU 2732 Leapin' Lizards(拆点+最大流)
HDU 2732 Leapin' Lizards 题目链接 题意:有一些蜥蜴在一个迷宫里面,有一个跳跃力表示能跳到多远的柱子,然后每根柱子最多被跳一定次数,求这些蜥蜴还有多少是不管怎样都逃不出来的. ...
- HDU2732 Leapin' Lizards —— 最大流、拆点
题目链接:https://vjudge.net/problem/HDU-2732 Leapin' Lizards Time Limit: 2000/1000 MS (Java/Others) M ...
- Leapin' Lizards [HDU - 2732]【网络流最大流】
题目链接 网络流直接最大流就是了,只是要拆点小心一个点的流超出了原本的正常范围才是. #include <iostream> #include <cstdio> #includ ...
随机推荐
- 加速下载gradle
http://www.jianshu.com/p/e887203e30f6 另外idea runconfiguration里边 gradle project要选项目根目录,而不是build脚本.
- Git系列教程一 入门与简介
一.版本控制引入 可能我们都会有这样的经历:创建了一个文件,并对它做了多次更改,当我们想回到其中的某一次更改的时候,由于时间太长记不得那次更改的内容,于是我们在每次大的更改的时候,会创建一个文件的副本 ...
- php取整函数ceil,floor,round,intval函数的区别
开发过程中,遇到数据处理取整的时候,你会用哪个呢,小涛来介绍一下:PHP取整函数有ceil,floor,round,intval,下面详细介绍一下: 1.ceil — 进一法取整说明float cei ...
- 函数式中的 currying
currying 是函数式语言中经常遇到的一个概念,翻译成 柯里化,不是库里化. currying 指的是将接收多个参数的函数变换成接收一个单一参数,并且返回接收余下的参数而且返回结果的新函数的技术. ...
- Source Insight 3.X utf8支持插件震撼发布
继上次SI多标签插件之后,因为公司内部编码改为utf8编码,因此特意做了这个Source Insight 3.X utf8插件. 下载地址:[点我] 安装说明: 解压msimg32.dll sihoo ...
- Sublime Text的心得经验。 全面
Sublime Text的心得经验.jikeytang/sublime-text · GitHub
- hive --service metastore 出现的问题
Could not create ServerSocket on address 0.0.0.0/0.0.0.0:9083 执行命令jps root@hadoopm:/usr# jps1763 Res ...
- mysql和CSV
1.mysql导入和导出数据可以通过mysql命令或者mysqldump来完成.mysqldump可以导入和导出完整的表结构和数据.mysql命令可以导入和导出csv文件. 1.mysql支持导入和导 ...
- mac常用的命令
1.递归查找⽂文件内容: grep -r target_string absolute_path 2.移动所有⽂文件(包括隐藏⽂文件): mv * .[^.]* targetDir 3.⽂文件分割合并 ...
- java字典序排序
import java.util.Comparator; import java.util.ArrayList; import java.util.Collections; public class ...