一中OJ #1735 藏宝图 | 棋盘Multi_SSP 多源最短路径 BFS | 解题报告

一中OJ | #1735 藏宝图

时限 1000MS/Case 内存 64MB/Case





题目描述

现在有一张藏宝图,类似一个迷宫,其中有一些障碍物(从一个无障碍格子可以上下左右走到相邻的无障碍格子中)。手动清除不同的障碍物耗时可能不同。图中的某一点藏有宝藏。有些点不可通过。在边界上有一些入口,有的入口会提供若干个炸药。用炸药清除障碍物和在迷宫中移动则认为不花费时间。一旦从某个入口进入迷宫,则不能再走到任何一个入口。例如下图表示一个迷宫:


    *#******A*
    *........*
    *9********
    *........*
    ********1*
    *$.......*

    **********


*表示无法通过的点,数字1..9表示障碍物以及清除该障碍物所需时间。“.”表示空地。“$”表示宝藏。“#”和字母‘A’..‘Z’都表示入口,#表示该入口无炸药提供,字母表示该入口提供的炸药数目。A表示一个炸药,B表示两个炸药,依次类推。迷宫的边框上只有#、*和字母。 

 

现给定一张地图,求从任意入口走到宝藏处最少所需单位时间。 

输入格式

输入一张地图,描述如上。

输出格式

如果能找到宝藏,则输出走到宝藏最少所需时间,否则输出"IMPOSSIBLE"。

样例输入

*#******A*
*........*
*9********
*........*
********1*
*$.......*
**********

样例输出

1

数据范围

地图的长宽大于等于3,小于等于100。

样例解释

上图如果选择从#进入迷宫,则不能再走进A。此时走到宝藏,则需要10个单位时间。如果选择从A进入迷宫则会提供1个炸药,炸掉9障碍物不花时间,手动清除1花费1个单位时间,所以总共只需1个单位时间即可。

----------------------------------------------------------

题目分析

棋盘最优路径BFS,只不过这次不是SSSP而是有多个入口的MSSP问题

计算最短路的话,跟普通的Dijkstra类似,只不过一开始在优先队列里多加几个出发点

重点在于状态的设计与转移,对于一个点,可以转移到周围的四个点(废话),每个点都有可能携带≤26个炸药包在身上

那么直接用dist[n][m][26]表示每一个状态,然后按照普通的图来转移即可

注意遇到一个障碍物的时候,转移两个点出来,一个炸,一个不炸

----------------------------------------------------------

代码

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <cctype>
#include <iomanip>
#define inf 0x7f7f7f7f
using namespace std;
char a[105][105];
int ans=inf,n,m,dist[105][105][30],dx[]={0,0,1,-1},dy[]={1,-1,0,0},destx,desty;
bool done[105][105][30]={false};
bool isdigit(char x)
{
	return x>='0' && x<='9';
}
struct state
{
	int x;
	int y;
	int b;
	int d;
	friend bool operator < (state a,state b)
	{
		return a.d>b.d;
	}
};
void dij()
{
	priority_queue<state>pq;
	for(int i=0;i<=n;i++) for(int j=0;j<=m;j++) for(int k=0;k<=28;k++) dist[i][j][k]=inf;
	for(int i=0;i<n;i++)
	for(int j=0;j<m;j++)
	{
		if(a[i][j]=='$')
		{
			destx=i;
			desty=j;
		}
		if(a[i][j]=='#' || (a[i][j]>='A' && a[i][j]<='Z'))
		{
			int bombs=0;
			if(a[i][j]>='A' && a[i][j]<='Z') bombs=a[i][j]-'A'+1;
			pq.push((state){i,j,bombs,0});
			dist[i][j][bombs]=0;
		}
	}
	
	while(!pq.empty())
	{
		state T=pq.top(); pq.pop();
		if(a[T.x][T.y]=='$') continue;
		if(done[T.x][T.y][T.b]) continue;
		done[T.x][T.y][T.b]=true;
		for(int i=0;i<4;i++)
		{
			state TT=(state){T.x+dx[i],T.y+dy[i],T.b,T.d};
			if(TT.x<0 || TT.y<0 || TT.x>=n || TT.y>=m) continue;
			if(a[TT.x][TT.y]=='*') continue;
			if(a[TT.x][TT.y]=='.' || a[TT.x][TT.y]=='$')
			{
				if(dist[TT.x][TT.y][TT.b]>TT.d)
				{
					dist[TT.x][TT.y][TT.b]=TT.d;
					pq.push(TT);
				}
			}
			if(isdigit(a[TT.x][TT.y]))
			{
				if(dist[TT.x][TT.y][T.b]>TT.d)//可以不放炸弹
				{
					dist[TT.x][TT.y][T.b]=TT.d+a[TT.x][TT.y]-'0';
					pq.push((state){TT.x,TT.y,TT.b,dist[TT.x][TT.y][T.b]});
				}
				if(dist[TT.x][TT.y][T.b-1]>TT.d && TT.b>0)//可以放炸弹
				{
					dist[TT.x][TT.y][T.b-1]=TT.d;
					TT.b--;
					pq.push(TT);
				}
			}
		}
	}
	return;
}
int main()
{
	while(~scanf("%s",a[n++]));
	n--;
	m=strlen(a[0]);
	dij();
	for(int i=0;i<=27;i++) ans=min(ans,dist[destx][desty][i]);
	if(ans==inf)
	{
		printf("IMPOSSIBLE\n");
		return 0;
	}
	cout<<ans;
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值