P3786 萃香抱西瓜

知识点:分层图,状态压缩,最短路,DP

原题面:Luogu

伊人不见隐何方,
吹散迷雾落月光,
萃取盛宴集佳酿,
香气溢满堂。

简述

无法简述的题面。

分析

稍有点细节的状压 DP。

读入时对所有时刻所有位置进行标记,记录是否有大小西瓜。

发现小西瓜个数较小,考虑状压一下获得的小西瓜状态。
\(s_{t,x,y}\) 表示 \(t\) 时刻,位置 \((x,y)\) 的小西瓜的存在状态。
\(f(t, x, y, S)\) 表示,在时间 \(t\),萃香的位置在 \((x,y)\),获得的小西瓜状态为 \(S\) 时,需要移动的最小步数。

初始化 \(f(1, sx, sy, s_{1,sx,sy}) = 0\),所有不可到达状态的 \(f = \operatorname{Inf}\)

转移时枚举每个时刻每个位置,从能到达该位置的上个时刻的位置 \((x',y')\) 转移过来,还需要枚举上个位置的小西瓜状态,有:

\[f(t,x,y,S|s_{t,x,y}) = \min\{f(t-1,x',y', S)\} + 1 \]

统计答案时枚举最后一个时刻的所有取完所有小西瓜的状态,取最小值即可。

复杂度 \(O(Thw2^m)\),数据范围小可以随便过。

注意数组大小。

代码

//知识点:分层图,状态压缩,最短路,DP 
/*
By:Luckyblock
注意数组大小 
*/
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#define LL long long
const int kMaxH = 5 + 1;
const int kMaxn = 20 + 1;
const int kMaxT = 100 + 1;
const int kMaxAll = (1 << 10) + 1;
const int kInf = 0x3f3f3f3f;
const int ex[5] = {0, 0, 0, 1, -1};
const int ey[5] = {0, 1, -1, 0, 0};
//=============================================================
int h, w, T, sx, sy;
int n, m, all, t1[kMaxn], t2[kMaxn];

int f[kMaxT][kMaxH][kMaxH][kMaxAll];
int s_num, s[kMaxT][kMaxH][kMaxH];
//=============================================================
inline int read() {
  int f = 1, w = 0;
  char ch = getchar();
  for (; !isdigit(ch); ch = getchar())
    if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
void Chkmax(int &fir_, int sec_) {
  if (sec_ > fir_) fir_ = sec_;
}
void Chkmin(int &fir_, int sec_) {
  if (sec_ < fir_) fir_ = sec_;
}
void Prepare() {
  h = read(), w = read(), T = read();
  sx = read(), sy = read();
  n = read(), m = read();
  for (int i = 1; i <= n; ++ i) {
    t1[i] = read(), t2[i] = read();
    int type = read();
    if (type) s_num ++;
    for (int j = t1[i]; j < t2[i]; ++ j) {
      int x = read(), y = read();
      s[j][x][y] = type ? (1 << (s_num - 1)) : -1;
    }
  }
}
//=============================================================
int main() {
  Prepare();
  if (s[1][sx][sy] == -1) {
    printf("-1");
    return 0;
  }
  
  all = (1 << m) - 1;
  memset(f, 0x3f, sizeof (f));
  f[1][sx][sy][s[1][sx][sy]] = 0;
  for (int i = 2; i <= T; ++ i) {
    for (int x = 1; x <= w; ++ x) {
      for (int y = 1; y <= h; ++ y) {
        if (s[i][x][y] == -1) continue ;
        for (int j = 0; j <= 4; ++ j) {
          int fx = x + ex[j], fy = y + ey[j]; //from
          if (fx < 1 || fx > w || fy < 1 || fy > h) continue ;
          if (s[i - 1][fx][fy] == -1) continue ;
          for (int k = 0; k <= all; ++ k) {
            Chkmin(f[i][x][y][k | s[i][x][y]],
                   f[i - 1][fx][fy][k] + (j > 0));
          }
        }
      }
    }
  }
  
  int ans = f[0][0][0][0];
  for (int x = 1; x <= w; ++ x) {
    for (int y = 1; y <= h; ++ y) {
      Chkmin(ans, f[T][x][y][all]);
    }
  }
  printf("%d\n", ans < kInf ? ans : -1);
  return 0;
}
posted @ 2020-11-11 16:14  Luckyblock  阅读(119)  评论(0编辑  收藏  举报