[洛谷P2472] [SCOI2007]蜥蜴

匿名 (未验证) 提交于 2019-12-02 23:49:02

蜥蜴

一道网络流,先来分析一下问题:
在一个\(r*c\)的图中分布了一些数,其他地方都用\(0\)填充,我们分别从指定的一些数出发,每次可以移动到周围距离为\(d\)以内的数上(或图外),原来的数会被\(-1\),任何时候数不能为负。各个数走法之间互相影响。问至多有多少个数出发能到达图外?

把这个题的限制条件列出来一下吧:

  • 每个石柱只能站一只蜥蜴
  • 每个石柱最多被经过其高度次
  • 石柱与石柱之间,石柱与图边界之间要距离小于等于\(d\)才能到达

首先我的角度是以每个石柱本身的限制条件入手。我们知道一个高度为\(h\)的石柱最多可以被经过\(h\)次(显然,蜥蜴是不走回头路的,因为这是对资源的浪费),而网络流的基本性质之一,是每条边最多将其上限流满(相当于有一个上限),那么可以考虑将石柱的高度作为网络流建图边上的限制。但是每个石柱是一个点,怎么办呢,我们就考虑把每个石柱拆点,把编号为\(i\)的点拆成\(i\)\(i + r * c\),然后把流入这个点的边全部接到\(i\)上,流出这个点的边全部接到\(i+r*c\)上,把限制加在两点之间的连边上(流量为\(h\))。这是对于石柱的处理,也是我认为这个问题中最关键的一步。

剩下的就比较好办了。
对于“每个石柱只能站一只蜥蜴”的限制条件,将“只能站一只”作为上界,源点向蜥蜴所在的每个石柱连边,边容量为\(1\)
对于石柱和石柱之间,石柱与图边界之间距离小于等于\(d\)才能到达的限制条件,因为图很小,我们考虑直接暴力枚举两个点,如果两个点都有石柱且距离小于等于\(d\),那么我们直接考虑两个石柱之间连一条容量为\(INF\)的边:除了距离,没有别的限制条件了,而距离的限制条件已经判断过了,并且每个石柱的限制已经在拆点的过程中加上去了,所以容量不需要做其他的限制,直接连\(INF\)即可。对于到达边界的限制条件,我们同样连一条\(INF\)的边(和前面的原因类似),距离判断只需要判断横纵就行,因为根据勾股定理,横纵都比\(d\)大显然斜着也比\(d\)大。

// luogu-judger-enable-o2 #include <bits/stdc++.h> #define INF (1000000000 + 7) #define N (10005 + 5) #define M (100000 + 5) #define int long long using namespace std; inline int read(){     int cnt = 0, f = 1; char c;     c = getchar();     while (!isdigit(c)) {         if(c == '-') f = -f;         c = getchar();     }     while (isdigit(c)) {         cnt = cnt * 10 + c - '0';         c = getchar();     }        return cnt * f; } int r, c, d, tot = 1, n; int S, T; int first[M], nxt[M], to[M], flow[M]; int mapp[N][N], a[N][N]; int dep[M], cnt[M]; char lizard[N][N]; inline void Add(int x, int y, int z) {     nxt[++tot] = first[x], first[x] = tot, to[tot] = y, flow[tot] = z;     nxt[++tot] = first[y], first[y] = tot, to[tot] = x, flow[tot] = 0; }  inline bool pd(int i, int j) {     if (i <= d || j <= d) return true;     if (r - i + 1 <= d || c - j + 1 <= d) return true;     return false; } inline void build() {     S = 1;     for (register int i = 1; i <= r; i++)         for (register int j = 1; j <= c; j++)             a[i][j] = ++tot;      for (register int i = 1; i <= r; i++)         scanf("%s", lizard[i] + 1);     for (register int i = 1; i <= r; i++)         for (register int j = 1; j <= c; j++)             mapp[i][j] = lizard[i][j] - '0';                  T = r * c * 2 + 2, tot = 1;      for (register int i = 1; i <= r; i++)             scanf("%s", lizard[i] + 1);           for (register int i = 1; i <= r; i++)         for (register int j = 1; j <= c; j++)              if (mapp[i][j]) {                 Add(a[i][j], a[i][j] + r * c, mapp[i][j]);                 if (pd(i, j)){                      Add(a[i][j] + r * c, T, INF); //                   cout<<i<<" "<<j<<endl;                 }             }                  for (register int i = 1; i <= r; i++)         for (register int j = 1; j <= c; j++)              for (register int k = 1; k <= r; k++)                  for (register int p = 1; p <= c; p++) {                     if (i == k && j == p) continue;                     if (mapp[i][j] && mapp[k][p])                     if ((i - k) * (i - k) + (j - p) * (j - p) <= d * d)                         Add(a[i][j] + r * c, a[k][p], INF); //                      Add(a[k][p] + r * c, a[i][j], INF);                     }     for (register int i = 1; i <= r; i++)         for (register int j = 1; j <= c; j++)             if (lizard[i][j] == 'L') Add(S, a[i][j], 1), ++n; } inline void bfs_(int s) {     memset(dep, 0xff, sizeof(dep));     dep[s] = 0;     cnt[0] = 1;     queue<int> q;     q.push(s);     while (!q.empty()) {         int p = q.front();         q.pop();         for (register int i = first[p]; i >= 2; i = nxt[i]) {             int v = to[i];             if (dep[v] == -1) {                 ++cnt[dep[v] = dep[p] + 1];                 q.push(v);             }         }     } }  int max_flow;  int dfs_(int p, int f) {     if (p == T) {         max_flow += f;         return f;     }     int u = 0;     for (register int i = first[p]; i >= 2; i = nxt[i]) {         int v = to[i];         if (flow[i] && dep[v] == dep[p] - 1) {             int uu = dfs_(v, min(flow[i], f - u));              if (uu) {                 flow[i] -= uu;                 flow[i ^ 1] += uu;                 u += uu;             }             if (u >= f) {                 return u;             }         }     }     if (!--cnt[dep[p]]) {         dep[S] = r * c * 2 + 10;     }     ++cnt[++dep[p]];     return u; } signed main() {     r = read(); c = read(); d = read();     build();     bfs_(T);     while (dep[S] < 2 * r * c + 9) dfs_(S, INF);     printf("%lld", n - max_flow);     return 0; }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!