LCP 13 bfs + 状态压缩 dp

58 篇文章 0 订阅
题意

传送门 LCP 13.寻宝

题解

bfs 求各机关点到地图各点的最短距离;遍历石碓求各机关点间经过石碓的最短距离;对经过的机关点状态压缩,记忆化搜索求解。

class Solution {
private:
int INF = 0x3f3f3f3f;
int dx[4] = {0, 0, -1, 1};
int dy[4] = {-1, 1, 0, 0};
int H, W, sX, sY, tX, tY, si, ti;
int dis[20][105][105];
int diso[20][20];
vector<int> oX, oY, mX, mY;
int dp[1 << 16][16];

void bfs(int x, int y, vector<string>& maze, int dis[105][105]){
	dis[x][y] = 0;
	queue<int> qx, qy;
	qx.push(x); qy.push(y);
	while(!qx.empty()){
		int x = qx.front(); qx.pop();
		int y = qy.front(); qy.pop();
		for(int i = 0; i < 4; i++){
			int nx = x + dx[i], ny = y + dy[i];
			if(nx >= 0 && nx < H && ny >= 0 && ny < W && maze[nx][ny] != '#' && dis[nx][ny] == INF){
				dis[nx][ny] = dis[x][y] + 1;
				qx.push(nx); qy.push(ny);
			}
		}
	}
}
// 状态压缩 dp
int rec(int S, int u){
    if(S == (1 << mX.size()) - 1){
        return dp[S][u] = dis[ti][mX[u]][mY[u]];
    }
    if(dp[S][u] != -1) return dp[S][u];
    
    int res = INF;
    for(int i = 0; i < mX.size(); i++){
        if(!((S >> i) & 1)){
            res = min(res, diso[i][u] + rec(S | (1 << i), i));
        }
    }
    return dp[S][u] = res;
}
    
public:
    int minimalSteps(vector<string>& maze) {
        H = maze.size(), W = maze[0].length();
        oX.clear(); oY.clear(); mX.clear(); mY.clear();
        for(int i = 0; i < H; i++){
            for(int j = 0; j < W; j++){
                if(maze[i][j] == 'S') sX = i, sY = j;
                else if(maze[i][j] == 'T') tX = i, tY = j;
                else if(maze[i][j] == 'O'){
                    oX.push_back(i); oY.push_back(j);
                }
                else if(maze[i][j] == 'M'){
                    mX.push_back(i); mY.push_back(j);
                }
            }
        }
        
        memset(dis, 0x3f, sizeof(dis));
        for(int i = 0; i < mX.size(); i++){
            bfs(mX[i], mY[i], maze, dis[i]);
        }
        si = mX.size(), ti = si + 1;
        bfs(sX, sY, maze, dis[si]); bfs(tX, tY, maze, dis[ti]);
        
        if(mX.size() == 0) return dis[si][tX][tY] >= INF ? -1 : dis[si][tX][tY];
        // 求 "O" 间经过 "M" 的最短距离
        for(int i = 0; i < mX.size(); i++){
            for(int j = i + 1; j < mX.size(); j++){
                int mincost = INF;
                for(int k = 0; k < oX.size(); k++){
                    mincost = min(mincost, dis[i][oX[k]][oY[k]] + dis[j][oX[k]][oY[k]]);
                }
                diso[i][j] = diso[j][i] = mincost;
            }
        }
        
        int res = INF;
        memset(dp, -1, sizeof(dp));
        for(int i = 0; i < mX.size(); i++){
            int mincost= INF;
            for(int j = 0; j < oX.size(); j++){
                mincost = min(mincost, dis[si][oX[j]][oY[j]] + dis[i][oX[j]][oY[j]]);
            }
            res = min(res, rec(1 << i, i) + mincost);
        }
        return res >= INF ? -1 : res;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值