一中OJ | #1735 藏宝图
时限 1000MS/Case 内存 64MB/Case
题目描述
现在有一张藏宝图,类似一个迷宫,其中有一些障碍物(从一个无障碍格子可以上下左右走到相邻的无障碍格子中)。手动清除不同的障碍物耗时可能不同。图中的某一点藏有宝藏。有些点不可通过。在边界上有一些入口,有的入口会提供若干个炸药。用炸药清除障碍物和在迷宫中移动则认为不花费时间。一旦从某个入口进入迷宫,则不能再走到任何一个入口。例如下图表示一个迷宫:
*........*
*9********
*........*
********1*
*$.......*
**********
现给定一张地图,求从任意入口走到宝藏处最少所需单位时间。
输入格式
输入一张地图,描述如上。
输出格式
如果能找到宝藏,则输出走到宝藏最少所需时间,否则输出"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;
}