500*500的平面,每格都有一个标记,表及含义如下:
标记:0 空白位置,在此处可以向上下左右四个方向走,保证0位置不超过100个。
标记:# 陷阱,走到此处会挂掉
标记:W 墙,这个位置不能走
标记:$ 盒子,在此处可以花费2秒打开盒子,取走钱,之后可以向上下左右四个方向走,保证$位置不超过10个。
标记:U,D,L,R 分别对应上下左右,在这个标记处,下一步只能按照标记的方向走。
由于0和$最多只有110个,所以可以把这些可以自由行动的点抽出来,重新建成一个图,也就是对原矩阵预处理一下。首先给这些点标下号,$在前(方便装压记录取钱情况)0在后,然后遍历矩阵,遍历到一个$或0时,枚举四个方向,看最近可以到达哪个$或0,同时记录话费,建成一个新图。预处理后就从起点开始BFS了,Dp[x][sta]表示在x节点,取钱状态为sta时的最小时间,每次扩展出一个新节点v时,若时间ti>dp[v][sta]就更新Dp的值,并且若v,sta这对状态没有在队列中就让它进队(类似SPFA)。最后便利一下dp[ed]的所有状态,找一个1最多的对应的时间输出就行了。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
typedef long long ll;
const int fx[4]={0,1,0,-1};
const int fy[4]={1,0,-1,0};
struct EG
{
int v,next,w;
}edge[42000];
int en;
int g[220];
const int inf=9999999;
char s[550][550];
int num[550][550];
int n,m,p,q,x,y,z,k;
int numa,numb;
bool vis[550][550];
bool check(int x,int y)
{
if (x>0 && x<=n && y>0 && y<=m && s[x][y]!='W' && s[x][y]!='#')
{
return true;
}
return false;
}
int trans(int x,int y,int &t)
{
memset(vis,false,sizeof vis);
while(s[x][y]!='0' && s[x][y]!='$')
{
t++;
if (s[x][y]=='L') y--;
else if (s[x][y]=='R') y++;
else if (s[x][y]=='U') x--;
else if (s[x][y]=='D') x++;
if (vis[x][y]) return -1;
if (!check(x,y)) return -1;
vis[x][y]=true;
}
return num[x][y];
}
int sx,sy,ex,ey;
int dp[220][2048];
bool inq[220][2048];
struct node
{
int id,sta;
node()
{
}
node(int x,int y)
{
id=x; sta=y;
}
};
int calc(int x)
{
int res=0;
while(x)
{
if (x&1) res++;
x>>=1;
}
return res;
}
void addedge(int u,int v,int w)
{
edge[en].v=v;
edge[en].w=w;
edge[en].next=g[u];
g[u]=en;
en++;
}
int main()
{
// freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
memset(num,-1,sizeof num);
numa=numb=0;
for (int i=1; i<=n; i++)
scanf("%s",&s[i][1]);
scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
{
if (s[i][j]=='$') num[i][j]=numb++;
}
numa=numb;
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
if (s[i][j]=='0') num[i][j]=numa++;
memset(g,-1,sizeof g);
en=0;
int tx,ty,ti;
int u,v;
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
if (num[i][j]!=-1)
{
u=num[i][j];
for (int k=0; k<4; k++)
{
tx=i+fx[k];
ty=j+fy[k];
ti=1;
if (check(tx,ty))
{
v=trans(tx,ty,ti);
if (v!=-1)
{
addedge(u,v,ti);
}
}
}
}
int st=num[sx][sy];
int ed=num[ex][ey];
queue<node> q;
while(!q.empty())
{
q.pop();
}
memset(dp,0x3f,sizeof dp);
q.push(node(st,0));
dp[st][0]=0;
inq[st][0]=true;
while(!q.empty())
{
int u=q.front().id;
int v;
int sta=q.front().sta;
q.pop();
inq[u][sta]=false;
int tu,ts,ti;
for (int j=g[u]; j!=-1; j=edge[j].next)
{
tu=u;
ts=sta;
ti=dp[u][sta];
v=edge[j].v;
ti+=edge[j].w;
if (v<numb)
{
if (((1<<v)&ts)==0)
{
ti+=2;
ts|=(1<<v);
}
}
if (dp[v][ts]>ti)
{
dp[v][ts]=ti;
if (!inq[v][ts])
{
q.push(node(v,ts));
inq[v][ts]=true;
}
}
}
}
int ans=inf,tt=-1;
for (int i=0; i<(1<<numb); i++)
{
int tmp=calc(i);
if (tmp>tt && dp[ed][i]<inf)
{
ans=dp[ed][i];
tt=tmp;
}
}
if (ans==inf) puts("-1");
else printf("%d\n",ans);
}
return 0;
}