[BZOJ1066] [SCOI2007] 蜥蜴 (网络流)

Posted CtrlCV

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1066] [SCOI2007] 蜥蜴 (网络流)相关的知识,希望对你有一定的参考价值。

Description

  在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃
到边界外。 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石
柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不
变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个
石柱上。

Input

  输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石竹的初始状态,0表示没有石柱
,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。

Output

  输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。

Sample Input

5 8 2
00000000
02000000
00321100
02000000
00000000
........
........
..LLLL..
........
........

Sample Output

1

HINT

  100%的数据满足:1<=r, c<=20, 1<=d<=4

Source

Solution

  类比网络流,每一只蜥蜴的路径就是一条$1$的流,柱子高度减小相当于流量上限减小,然后就可以类比着构出网络流的图:

  将每一个柱子拆成两个点,之间连边,流量为这根柱子的高度,借用黄学长的说法,相当于柱子底部到柱子顶部连一条边

  超级源点向所有有蜥蜴的柱子连$1$的边,所有可以跳出地图的柱子向超级汇点连$INF$的边(由于单次最大流不超过$400$所以这里边权我写的$400$)

  如果一根柱子可以到达另一根,就把该柱子的顶连到另一根的底部,边权$INF$(嗯。。。)

  用总蜥蜴数减最大流就是剩下的蜥蜴数

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 struct edge
 4 {
 5     int v, w, nxt;
 6 }e[30005];
 7 int r, c, fst[805], h[25][25], level[805], q[805], etot = 1;
 8 char s[25];
 9 
10 void addedge(int u, int v, int w)
11 {
12     e[++etot] = (edge){v, w, fst[u]}, fst[u] = etot;
13     e[++etot] = (edge){u, 0, fst[v]}, fst[v] = etot;
14 }
15 
16 int BFS()
17 {
18     int front = 0, back, u;
19     memset(level, 0, sizeof(level));
20     level[2 * r * c + 1] = 1, q[back = 1] = 2 * r * c + 1;
21     while(front != back)
22     {
23         u = q[++front];
24         for(int i = fst[u]; i; i = e[i].nxt)
25             if(e[i].w && !level[e[i].v])
26             {
27                 level[e[i].v] = level[u] + 1;
28                 q[++back] = e[i].v;
29             }
30     }
31     return level[2 * r * c + 2];
32 }
33 
34 int Dinic(int u, int lim)
35 {
36     int tmp = lim;
37     if(u == 2 * r * c + 2) return lim;
38     for(int i = fst[u]; i; i = e[i].nxt)
39         if(e[i].w && level[e[i].v] == level[u] + 1)
40         {
41             int flow = Dinic(e[i].v, min(tmp, e[i].w));
42             e[i].w -= flow, e[i ^ 1].w += flow;
43             if(!(tmp -= flow)) break;
44         }
45     if(tmp == lim) level[u] = 0;
46     return lim - tmp;
47 }
48 
49 int main()
50 {
51     int d, ans = 0;
52     scanf("%d%d%d", &r, &c, &d);
53     for(int i = 0; i < r; ++i)
54     {
55         scanf("%s", s + 1);
56         for(int j = 1; j <= c; ++j)
57         {
58             h[i + 1][j] = s[j] - 48;
59             addedge(i * c + j, (r + i) * c + j, h[i + 1][j]);
60         }
61     }
62     for(int i = 0; i < r; ++i)
63     {
64         scanf("%s", s + 1);
65         for(int j = 1; j <= c; ++j)
66             if(s[j] == \'L\')
67                 ++ans, addedge(2 * r * c + 1, i * c + j, 1);
68     }
69     for(int i = 0; i < r; ++i)
70         for(int j = 1; j <= c; ++j)
71             if(h[i + 1][j] && (i < d || i >= r - d || j <= d || j > c - d))
72                 addedge((r + i) * c + j, 2 * r * c + 2, 400);
73     for(int i = d; i < r - d; ++i)
74         for(int j = d + 1; j <= c - d; ++j)
75             if(h[i + 1][j])
76                 for(int k = -d; k <= d; ++k)
77                     for(int l = -d; l <= d; ++l)
78                         if(h[i + k + 1][j + l] && k * k + l * l <= d * d)
79                             addedge((r + i) * c + j, (i + k) * c + j + l, 400);
80     while(BFS())
81         ans -= Dinic(2 * r * c + 1, 400);
82     printf("%d\\n", ans);
83     return 0;
84 }
View Code

 

以上是关于[BZOJ1066] [SCOI2007] 蜥蜴 (网络流)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1066: [SCOI2007]蜥蜴

BZOJ 1066: [SCOI2007]蜥蜴

BZOJ1066: [SCOI2007]蜥蜴

bzoj1066SCOI2007蜥蜴

BZOJ 1066[SCOI2007]蜥蜴

bzoj1066[SCOI2007]蜥蜴 最大流