首先,此题32M的空间决定不能开200*200*128*4的int型,不能太暴力。。
还有,明显不能一小步一小步,而要一条一条走。
读入图的外边界不是障碍物,所以会滑出去,而不能停在那里继续走。
但是经过E且从E出去(即最后一步)又是个例外。
方法一【28M左右】:
每个点怎么走与之前到这个点的方向没有关系。
如果是RDUL,接下来这步的方向就确定了
如果是障碍物边上的点,可以向没有被障碍物挡住的任一边走,
甚至可以怎么来的怎么回去。
(可能为了拿把钥匙,当然绝大多数情况只是在浪费步数(那是之后的事),但是必须不能漏这个方向)
因此,预处理出每个【可停留点】向四周到达的点,这条路上的钥匙,这条路上是否有出口。
最后从S开始求最短路即可(因为RDUL型不算步数,权值有0有1)
最短路核心部分//CLEAR Qx、Qy和Qs;
Qx.push(sx);Qy.push(sy);Qs.push(0);
dp[0][sx][sy]=0;
while(!Qx.empty()){
int x=Qx.front(),y=Qy.front(),s=Qs.front();
Qx.pop();Qy.pop();Qs.pop();
for(int d=0;d<4;++d){
【更新答案】如果加一条路可以更新答案(钥匙够了&&门走路上)就更新答案;
【更新队列】如果可以更新路的另一端就更新,并加到队列中 (前提是路的另一端是个【图内点】)
}
}
那。。。E算不算一个【可停留点】?
不算,可停留点必须要满足一个性质——到可停留点和出可停留点不属于同一条路,
即方向不同(右和右算相同,右和左、上、下算不同)
不然,两条路一合,答案就更小了。。。
(E是可以出的,当钥匙未满时)
那么那些属于【可停留点】?
比如说预处理向上方向时,这些均属于可停留点。(很容易漏的)
1.读入图的外边界(但它们不属于【图内点】,求最短路更新队列时要注意)
2.上一格是障碍物的点,且这格不是障碍物
3.这格是R、D、L(注意没有U)
好了,最后还有一个坑。。一条路上既有E也有钥匙,拿完钥匙再到出口还是
到出口时后面还有未曾拿到过的钥匙。。。
所以预处理时还要预处理这条路到出口前能拿到的钥匙。求最短路更新答案时用。
方法二【28M左右】:
之前贴的方法二有误,8月3日中午13点更新代码
到达RDUL模拟最终停在那里(要处理形成环的情况,永远走不完的情况)
这样每条路的权值只有1了,最后广搜即可。
方法三【1M左右】:(照着标称打了一遍)
最多只有9个【特殊点】,S+E+K
预处理出d[9][4][9][4](对每个【特殊点】四种方向(前面的9 4)全图的bfs,
取有用的记录到dp里(后面的9 4))
d[i][k1][j][k2]代表从i点出发沿k1方向到达j点为k2方向时的最小步数
再求dp[9][127][4]
dp[i][j][k]从S点任一方向,k方向到i【特殊点】,钥匙状态为j至少用了几步
最后从dp[][所有钥匙][]更新到答案里去
题外话:标程是有欠缺的,hdu在8月2日晚饭左右时间加强了数据,于是标程跪了。
(题解里有原话——注意一个强制拐弯的格子如果强制方向的下一个格子是墙,那么它将永远卡住。)
但标程却没有考虑,估计放错程序了。
给出一组数据
3 3
RKD
S#E
UKL
ans=1;
//方法一
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define N 205
using namespace std;
const int INF=0x3f3f3f3f;
struct str1{
int k1,k2,p,ck;
};
int a[N][N];
char s[N];
str1 pre[N][N][4];
int dp[1<<7][N][N];
int n,m,sx,sy,ex,ey,tot,ma,ans;
queue<int> Qx,Qy,Qs;
void clear()
{ while (!Qx.empty()) Qx.pop();
while (!Qy.empty()) Qy.pop();
while (!Qs.empty()) Qs.pop();
}
bool minimize(int &p,int q)
{ if(p<=q)return 0;
p=q;
return 1;
}
void prepare0();
void prepare1();
void prepare2();
void prepare3();
void bfs()
{ int tmp;
ans=INF; memset(dp,0x3f,sizeof(dp));
clear();
Qx.push(sx);Qy.push(sy);Qs.push(0);
dp[0][sx][sy]=0;
while(!Qx.empty())
{ int x=Qx.front(),y=Qy.front(),s=Qs.front();
Qx.pop();Qy.pop();Qs.pop();
for(int d=0;d<4;++d)
{ if (a[x][y]>=-8&&a[x][y]<=-5&&a[x][y]+8!=d) continue;
if (pre[x][y][d].p==-1) continue;
if (a[x][y]>=-8&&a[x][y]<=-5)tmp=0;else tmp=1;
int tx=pre[x][y][d].p/N,ty=pre[x][y][d].p%N,ts=s|pre[x][y][d].k1;
if(pre[x][y][d].ck&&((s|pre[x][y][d].k2)==ma)) minimize(ans,dp[s][x][y]+tmp);
if (tx<1||tx>n||ty<1||ty>m)continue;
if(minimize(dp[ts][tx][ty],dp[s][x][y]+tmp))
{Qx.push(tx);Qy.push(ty);Qs.push(ts);}
}
}
if(ans==INF)printf("-1\n");else printf("%d\n",ans);
}
void doit()
{ char c;
tot=0;
for (int i=0;i<=n+1;i++)
for (int j=0;j<=m+1;j++)
a[i][j]=-1;
for (int i=1;i<=n;i++)
{scanf("%s",s);
for (int j=1;j<=m;j++)
{c=s[j-1];
if (c=='#') a[i][j]=-2;
if (c=='.') a[i][j]=-1;
if (c=='S') {a[i][j]=-3; sx=i;sy=j;}
if (c=='E') {a[i][j]=-4; ex=i;ey=j;}
if (c=='K') {a[i][j]=1<<tot;tot++;}
if (c=='L') a[i][j]=-8;
if (c=='R') a[i][j]=-7;
if (c=='U') a[i][j]=-6;
if (c=='D') a[i][j]=-5;
}
}
ma=1<<tot;
ma--;
memset(pre,255,sizeof(pre));
int i,j;
i=0;
for (j=0;j<=m+1;j++)
for (int t=0;t<4;t++)
{pre[i][j][t].p=i*N+j;
pre[i][j][t].k1=pre[i][j][t].k2=pre[i][j][t].ck=0;
}
i=n+1;
for (j=0;j<=m+1;j++)
for (int t=0;t<4;t++)
{pre[i][j][t].p=i*N+j;
pre[i][j][t].k1=pre[i][j][t].k2=pre[i][j][t].ck=0;
}
j=0;
for (i=1;i<=n;i++)
for (int t=0;t<4;t++)
{pre[i][j][t].p=i*N+j;
pre[i][j][t].k1=pre[i][j][t].k2=pre[i][j][t].ck=0;
}
j=m+1;
for (i=1;i<=n;i++)
for (int t=0;t<4;t++)
{pre[i][j][t].p=i*N+j;
pre[i][j][t].k1=pre[i][j][t].k2=pre[i][j][t].ck=0;
}
prepare0();
prepare1();
prepare2();
prepare3();
bfs();
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF) doit();
return 0;
}
void prepare0()
{ int t=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (a[i][j]!=-2)
{ int tmp=a[i][j]>=0?a[i][j]:0;
if (a[i][j-1]==-2||a[i][j]==-5||a[i][j]==-7||a[i][j]==-6)
{pre[i][j][t].p=i*N+j;
pre[i][j][t].k1=tmp;
pre[i][j][t].k2=tmp;
pre[i][j][t].ck=(a[i][j]==-4);
}
else
{pre[i][j][t].p=pre[i][j-1][t].p;
pre[i][j][t].ck=pre[i][j-1][t].ck||(a[i][j]==-4);
pre[i][j][t].k1=pre[i][j-1][t].k1+tmp;
pre[i][j][t].k2=pre[i][j-1][t].k2+pre[i][j][t].ck*tmp;
}
}
}
void prepare1()
{ int t=1;
for (int i=1;i<=n;i++)
for (int j=m;j>=1;j--)
if (a[i][j]!=-2)
{ int tmp=a[i][j]>=0?a[i][j]:0;
if (a[i][j+1]==-2||a[i][j]==-5||a[i][j]==-8||a[i][j]==-6)
{pre[i][j][t].p=i*N+j;
pre[i][j][t].k1=tmp;
pre[i][j][t].k2=tmp;
pre[i][j][t].ck=(a[i][j]==-4);
}
else
{pre[i][j][t].p=pre[i][j+1][t].p;
pre[i][j][t].ck=pre[i][j+1][t].ck||(a[i][j]==-4);
pre[i][j][t].k1=pre[i][j+1][t].k1+tmp;
pre[i][j][t].k2=pre[i][j+1][t].k2+pre[i][j][t].ck*tmp;
}
}
}
void prepare2()
{ int t=2;
for (int j=1;j<=m;j++)
for (int i=1;i<=n;i++)
if (a[i][j]!=-2)
{ int tmp=a[i][j]>=0?a[i][j]:0;
if (a[i-1][j]==-2||a[i][j]==-8||a[i][j]==-7||a[i][j]==-5)
{pre[i][j][t].p=i*N+j;
pre[i][j][t].k1=tmp;
pre[i][j][t].k2=tmp;
pre[i][j][t].ck=(a[i][j]==-4);
}
else
{pre[i][j][t].p=pre[i-1][j][t].p;
pre[i][j][t].ck=pre[i-1][j][t].ck||(a[i][j]==-4);
pre[i][j][t].k1=pre[i-1][j][t].k1+tmp;
pre[i][j][t].k2=pre[i-1][j][t].k2+pre[i][j][t].ck*tmp;
}
}
}
void prepare3()
{ int t=3;
for (int j=1;j<=m;j++)
for (int i=n;i>=1;i--)
if (a[i][j]!=-2)
{ int tmp=a[i][j]>=0?a[i][j]:0;
if (a[i+1][j]==-2||a[i][j]==-8||a[i][j]==-7||a[i][j]==-6)
{pre[i][j][t].p=i*N+j;
pre[i][j][t].k1=tmp;
pre[i][j][t].k2=tmp;
pre[i][j][t].ck=(a[i][j]==-4);
}
else
{pre[i][j][t].p=pre[i+1][j][t].p;
pre[i][j][t].ck=pre[i+1][j][t].ck||(a[i][j]==-4);
pre[i][j][t].k1=pre[i+1][j][t].k1+tmp;
pre[i][j][t].k2=pre[i+1][j][t].k2+pre[i][j][t].ck*tmp;
}
}
}
//方法二
#include <iostream>
#include <numeric>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
#pragma comment(linker,"/STACK:1024000000,1024000000")
using namespace std;
const int INF = 0x3f3f3f3f;
char Map[205][205];
int S[205][205],D[4][205][205],W[4][205][205],E[4][205][205],SE[4][205][205],dir[4][2]={0,-1,-1,0,1,0,0,1};
int dp[1<<7][205][205];
template<typename X>inline bool minimize(X&p,X q){if(p<=q)return 0;p=q;return 1;}
template<typename X>inline bool maximize(X&p,X q){if(p>=q)return 0;p=q;return 1;}
int check(int x,int y,int d){
if(Map[x][y]=='L')return 0;
if(Map[x][y]=='U')return 1;
if(Map[x][y]=='D')return 2;
if(Map[x][y]=='R')return 3;
return d;
}
void dfs(int x,int y,int d){
if(D[d][x][y])return;
D[d][x][y]=-(x*205+y);
W[d][x][y]|=S[x][y];
int tx=x+dir[d][0],ty=y+dir[d][1],td=check(tx,ty,d);
if(Map[tx][ty]=='*'){D[d][x][y]=tx*205+ty;return;}
if(Map[tx][ty]=='#'){D[d][x][y]= x*205+ y;return;}
dfs(tx,ty,td);
D[d][x][y] = D[td][tx][ty];
W[d][x][y]|= W[td][tx][ty];
E[d][x][y]|= E[td][tx][ty];
if(E[d][x][y])SE[d][x][y]|=S[x][y];
if(D[d][x][y]==-(x*205+y)){
D[d][x][y]=x*205+y;SE[d][x][y]=W[d][x][y];
while(tx!=x||ty!=y||td!=d){
D[td][tx][ty]=tx*205+ty;
W[td][tx][ty]=W[d][x][y];
E[td][tx][ty]=E[d][x][y];
SE[td][tx][ty]=SE[d][x][y];
tx+=dir[td][0];ty+=dir[td][1];
td=check(tx,ty,td);
}
}
}
int main(){
int N,M,sx,sy,ex,ey;
while(~scanf("%d%d",&N,&M)){
memset(Map,'*',sizeof(Map));
memset(D,0,sizeof(D));
memset(W,0,sizeof(W));
memset(S,0,sizeof(S));
memset(E,0,sizeof(E));
memset(SE,0,sizeof(SE));
memset(dp,0x3f,sizeof(dp));
int tot=0;
for(int i=1;i<=N;++i)
for(int j=1;j<=M;++j){
scanf(" %c",&Map[i][j]);
if(Map[i][j]=='K')S[i][j]=1<<tot++;
if(Map[i][j]=='S')sx=i,sy=j;
if(Map[i][j]=='E')ex=i,ey=j,E[0][i][j]=E[1][i][j]=E[2][i][j]=E[3][i][j]=1;
}
int Maxs=(1<<tot)-1,ans=INF;
for(int i=1;i<=N;++i)
for(int j=1;j<=M;++j)if(Map[i][j]!='#')
for(int d=0;d<4;++d)dfs(i,j,check(i,j,d));
queue<int> Qx,Qy,Qs;
Qx.push(sx);Qy.push(sy);Qs.push(0);
dp[0][sx][sy]=0;
while(!Qx.empty()){
int x=Qx.front(),y=Qy.front(),s=Qs.front();
Qx.pop();Qy.pop();Qs.pop();
for(int d=0;d<4;++d)if (D[d][x][y]){
int tx=D[d][x][y]/205,ty=D[d][x][y]%205,ts=s|W[d][x][y];
if(ts==Maxs&&E[d][x][y]&&(s|SE[d][x][y])==Maxs)minimize(ans,dp[s][x][y]+1);
if(Map[tx][ty]!='*'&&minimize(dp[ts][tx][ty],dp[s][x][y]+1)){
Qx.push(tx);
Qy.push(ty);
Qs.push(ts);
}
}
}
if(ans==INF)printf("-1\n");
else printf("%d\n",ans);
}
return 0;
}
//方法三
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define N 205
using namespace std;
const int INF=0x3f3f3f3f;
char s[N][N];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int map[N][N][4];
int d[9][4][9][4];
int n,m,ex,ey,tot,ma;
queue<int> Qx,Qy,Qd;
int tr[9][2];
int dp[9][1<<7][4];
void clear()
{ while (!Qx.empty()) Qx.pop();
while (!Qy.empty()) Qy.pop();
while (!Qd.empty()) Qd.pop();
}
void bfs(int x,int y,int d)
{ memset(map,0x3f,sizeof(map));
map[x][y][d]=0;
int tx=x+dx[d],ty=y+dy[d],td=d;
while (tx>=0&&tx<n&&ty>=0&&ty<m&&s[tx][ty]!='#')
{if (map[tx][ty][td]<=0) break;
map[tx][ty][td]=0;
if (s[tx][ty]=='L'&&td!=3) td=3;
else if (s[tx][ty]=='R'&&td!=1) td=1;
else if (s[tx][ty]=='U'&&td!=2) td=2;
else if (s[tx][ty]=='D'&&td!=0) td=0;
else {tx+=dx[td];ty+=dy[td];}
}
if (tx>=0&&tx<n&&ty>=0&&ty<m&&s[tx][ty]=='#')
{tx-=dx[td];ty-=dy[td];
//标程漏了下一个if
if (s[tx][ty]=='L'||s[tx][ty]=='R'||s[tx][ty]=='U'||s[tx][ty]=='D') return;
}
else return;
clear();
Qx.push(tx);Qy.push(ty);Qd.push(td);
while(!Qx.empty())
{ int nx=Qx.front(),ny=Qy.front(),nd=Qd.front(),dep=map[nx][ny][nd]+1;
Qx.pop();Qy.pop();Qd.pop();
for (int i=0;i<4;i++)if (i!=nd)
{
if (map[nx][ny][i]<=dep) continue;
map[nx][ny][i]=dep;
int tx=nx+dx[i],ty=ny+dy[i],td=i;
while (tx>=0&&tx<n&&ty>=0&&ty<m&&s[tx][ty]!='#')
{if (map[tx][ty][td]<=dep) break;
map[tx][ty][td]=dep;
if (s[tx][ty]=='L'&&td!=3) td=3;
else if (s[tx][ty]=='R'&&td!=1) td=1;
else if (s[tx][ty]=='U'&&td!=2) td=2;
else if (s[tx][ty]=='D'&&td!=0) td=0;
else {tx+=dx[td];ty+=dy[td];}
}
if (tx>=0&&tx<n&&ty>=0&&ty<m&&s[tx][ty]=='#')
{tx-=dx[td];ty-=dy[td];
//标程漏了下一个if
if (!(s[tx][ty]=='L'||s[tx][ty]=='R'||s[tx][ty]=='U'||s[tx][ty]=='D'))
{Qx.push(tx);Qy.push(ty);Qd.push(td);}
}
}
}
}
void doit()
{ char c;
tot=0;
for (int i=0;i<n;i++)
scanf("%s",s[i]);
for (int i=0;i<n;i++)
for (int j=0;j<m;j++)
{c=s[i][j];
if (c=='S') {tr[0][0]=i; tr[0][1]=j;}
if (c=='E') {ex=i;ey=j;}
if (c=='K') {tot++;tr[tot][0]=i;tr[tot][1]=j;}
}
tot++;
tr[tot][0]=ex;
tr[tot][1]=ey;
ma=1<<(tot-1);
for (int i=0;i<tot;i++)
for (int j=0;j<4;j++)
{bfs(tr[i][0],tr[i][1],j);
for (int i1=0;i1<=tot;i1++)
for (int j1=0;j1<4;j1++)
d[i][j][i1][j1]=map[tr[i1][0]][tr[i1][1]][j1];
}
memset(dp,0x3f,sizeof(dp));
for (int i=0;i<4;i++) dp[0][0][i]=1;
for (int j=0;j<ma;j++)
for (int i=0;i<tot;i++)
for (int k=0;k<4;k++)
{int tmp=dp[i][j][k];
if (tmp==INF) continue;
for (int i1=1;i1<tot;i1++)
for (int k1=0;k1<4;k1++)
{ int j1=j|(1<<(i1-1));
dp[i1][j1][k1]=min(dp[i1][j1][k1],tmp+d[i][k][i1][k1]);
}
}
int ans=INF;
for (int i=0;i<tot;i++)
for (int j=0;j<4;j++)
for (int k=0;k<4;k++)
ans=min(ans,dp[i][ma-1][j]+d[i][j][tot][k]);
if (ans==INF) printf("%d\n",-1);else printf("%d\n",ans);
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF) doit();
return 0;
}