题解 【萃香抱西瓜】

题面

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


posted @ 2020-11-05 14:18  zxsoul  阅读(121)  评论(0)    收藏  举报