题面
-
一个 (w imes h) 的矩阵,矩阵中存在可移动的 (0) 点 和 (1) 点
-
(0)点不可到达,(1) 可到达
-
给定一个起点 ((sx,sy)), 求给定时间 (T) 内可到达 (m) 个 (1) 所用的最小步数
数据范围
(1le h, wle 5, 1le Tle 100, 1le t1le T)
(2le t, 2le T+1, t1<t2)
(1le nle 20, 0le mle 10, mle n)
思路
-
数据范围不大,可以状压(DP)
-
用二进制数表示当前已有西瓜的状态,转移时就需要位运算
-
[f[t][i][j][k] ]
-
表示在 (T) 时刻,坐标为((i ,j))点上已经获得 (k) 个西瓜的最小步数
-
我们可用以个 (s[t][i][j]) 记录 (T) 时刻,坐标为((i ,j)) 点上可获得西瓜的数量
-
因此就可方程转移啦
-
[f[t][i][j][k | s[t][i][j]] = min{(f[t - 1][qx][qy][k])+1} ]
-
((qx qy))表示 (T - 1) 时刻的位置
-
字面上说,当前状态是由(f[t-1][i][j][k])状态 (+1) 转移来的
-
初始状态是(f[1][sx][sy][s[1][sx][sy]] = 0),其他为 (INF)
Code
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int sum,h,w,t,sx,sy,n,m,t1[manx],t2[manx];
int dx[5] = {0, 0, 0, 1, -1};
int dy[5] = {0, 1, -1, 0, 0};
int s[109][10][10],f[109][10][10][(1 << 10) + 1];
int main(){
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 p = read();
if(p) sum ++;
for(int j = t1[i];j < t2[i]; j++){
int x = read(),y = read();
if(p == 0) s[j][x][y] = -1;//只要当前时间(x,y)有一个是大西瓜,那么这个格子就不能走
else s[j][x][y] = 1 << (sum - 1);//-1的原因同下
}
}
if(s[1][sx][sy] == -1){cout<<-1;return 0;} //特判:落地成盒
ll bz = (1 << m) - 1;//10000000000(10) - 1=111111111(9)
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 qx = x + dx[j],qy = y + dy[j];
if(qx < 1||qy > h||qy < 1|| qx > w) continue;
if(s[i - 1][qx][qy] == -1) continue;
for(int k = 0;k <= bz;k ++){
f[i][x][y][k | s[i][x][y]] = min(f[i][x][y][k | s[i][x][y]],
f[i - 1][qx][qy][k] + (j > 0)); //转移方程式
}
}
}
int ans = f[0][0][0][0];
for(int x = 1;x <= w; x ++)
for(int y = 1;y <= h; y++){
ans = min(ans,f[t][x][y][bz]); //枚举满足条件的f
}
if(ans < inf) cout<<ans;
else cout<<-1;
return 0;
}