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; }