题解 【萃香抱西瓜】
题面
-
一个 \(w\times h\) 的矩阵,矩阵中存在可移动的 \(0\) 点 和 \(1\) 点
-
\(0\)点不可到达,\(1\) 可到达
-
给定一个起点 \((sx,sy)\), 求给定时间 \(T\) 内可到达 \(m\) 个 \(1\) 所用的最小步数
数据范围
\(1\le h,\ w\le 5,\ 1\le T\le 100,\ 1\le t1\le T\)
\(2\le t,\ 2\le T+1,\ t1<t2\)
\(1\le n\le 20,\ 0\le m\le 10,\ m\le 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;
}

你的萃香
浙公网安备 33010602011771号