题解 【萃香抱西瓜】

题面

  • 一个 (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;
}


原文地址:https://www.cnblogs.com/lToZvTe/p/13931431.html