题意:
wanghang现在玩一个游戏,他一个迷宫中。他的起点在S,他想到达E点的出口,出口的位置有守卫,他必须在迷宫中收集至少K个金币,才能买通守卫,放他出去。守卫是十分暴躁的,如果他到达出口的位置时身上的金币不足K个的话,守卫就会把wanghang杀掉,这样就GAME OVER了。这个迷宫中还有多个传送门,每次使用传送门需要花费1金币,可以传送到任意一个传送门的位置。
wanghang想尽快通关这个游戏,现在问最少需要多少步可以走出迷宫?
如图:
#######
#E...P#
#...SP#
#.CCC.#
#######
地图中,
#代表墙壁,
.代表空地,
P代表传送门,(传送门个数<=5)
C代表金币,金币不能重复拾取(金币个数<=5)
S,E代表起点,出口(保证只会仅出现一个S和E)
每次可以朝上下左右四个方向移动,使用传送门也算1步。
思路:
显然是一个状态压缩和然后在结合一下记忆化搜索
用一个四维数组vis[][][][]第一维表示x第二维表示y,第三位表示当前所吃的金币的状态(5位二进制对应10进制),第三维表示当前的拥有的金币。
bfs里有5个 元素,x,y,g(上面的二进制状态),v(上面拥有的财富),st当前步骤数
代码:
#include <bits/stdc++.h>
using namespace std;
#define maxn 311111
#define mod 1000000007
typedef long long LL;
char cmp[15][15]; //字符地图
bool vis[15][15][40][10]; //状态标记
int mp[15][15]; //数字地图
bool mvis[15][15]; //没用到
int godx[10],gody[10]; //金币位置
int px[10],py[10]; //传送门位置
int stepx[5]={0,1,0,-1,0}; //步骤
int stepy[5]={0,0,1,0,-1};
int n,m,k;
int head,wei;
struct NODE {
int x,y,g,v,st; //横纵坐标,金币状态值(五位二进制)。所拥有价值,步骤数
}bfs[111111];
int pan(int x,int y) { //判断这个点是不是在地图内
if(x>=1&&y>=1&&x<=n&&y<=m) return 1;
return 0;
}
void bb(int x,int y,int g,int v,int st,int nn) { //自定义bfs数组添加方法
bfs[nn].x=x;
bfs[nn].y=y;
bfs[nn].g=g;
bfs[nn].v=v;
bfs[nn].st=st;
}
int main () {
//freopen("1.txt","r",stdin);
int t;
int fa;
int god,p;
int sx,sy,ex,ey; //起始点,终点
scanf("%d",&t);
while(t--) {
fa=0;
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<n;i++) {
scanf("%s",cmp[i]);
}
god=0;p=0;
memset(mp,0,sizeof mp);
memset(mvis,0,sizeof mvis);
memset(vis,0,sizeof vis);
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
if(cmp[i][j]=='#') {
mp[i+1][j+1]=1;
}
if(cmp[i][j]=='.') {
mp[i+1][j+1]=0;
}
if(cmp[i][j]=='C') {
mp[i+1][j+1]=2;
god++;
godx[god]=i+1;
gody[god]=j+1;
}
if(cmp[i][j]=='S') {
mp[i+1][j+1]=0;
sx=i+1;
sy=j+1;
}
if(cmp[i][j]=='E') {
mp[i+1][j+1]=0;
ex=i+1;
ey=j+1;
}
if(cmp[i][j]=='P') {
mp[i+1][j+1]=3;
p++;
px[p]=i+1;
py[p]=j+1;
}
}
}
// for(int i=1;i<=n;i++) {
// for(int j=1;j<=m;j++)
// cout << mp[i][j] <<" " ;
// cout << endl;
// }
// cout <<"god" <<god << endl;
// for(int i=1;i<=god;i++)
// cout << godx[i] << " " << gody[i] << endl;
// cout <<"p" << p << endl;
// for(int i=1;i<=p;i++)
// cout << px[i] << " " << py[i] << endl;
bfs[1].x=sx;
bfs[1].y=sy;
bfs[1].g=0;
bfs[1].v=0;
bfs[1].st=0;
vis[sx][sy][0][0]=1;
head=1;
wei=2;
while(head<wei) {
if(fa==1) break;
if(mp[bfs[head].x][bfs[head].y]==3) { //如果bfs[head]是传送门的话就另外处理
int xx=bfs[head].x;
int yy=bfs[head].y;
int gg=bfs[head].g;
int vv=bfs[head].v;
int st=bfs[head].st+1;
int lox=0;
for(int j=1;j<=p;j++)
if(xx==px[j]&&yy==py[j]) {
lox=j;
break;
}
for(int j=1;j<=p;j++) {
if(j!=lox) {
if(vv>0&&!vis[px[j]][py[j]][gg][vv-1]) {
bb(px[j],py[j],gg,vv-1,st,wei);
wei++;
vis[px[j]][py[j]][gg][vv-1]=1;
}
}
}
// head++;
// continue;
}
for(int i=1;i<=4;i++) { //正常的朝四个方向前进
int xx=bfs[head].x+stepx[i];
int yy=bfs[head].y+stepy[i];
int gg=bfs[head].g;
int vv=bfs[head].v;
int st=bfs[head].st+1;
int lox=0;
if(!pan(xx,yy)) {
continue;
}
if(mp[xx][yy]==1) {
continue;
}
if(xx==ex&&yy==ey) {
if(vv>=k) {
printf("%d\n",st);
fa=1;
break;
}
else {
continue;
}
}
if(mp[xx][yy]==2) {
for(int j=1;j<=god;j++) {
if(xx==godx[j]&&yy==gody[j]) {
lox=j;
break;
}
}
if(!(gg&(1<<(lox-1)))) {
if(!vis[xx][yy][gg|(1<<(lox-1))][vv+1]) {
bb(xx,yy,gg|(1<<(lox-1)),vv+1,st,wei);
wei++;
vis[xx][yy][gg|(1<<(lox-1))][vv+1]=1;
}
}
else {
if(!vis[xx][yy][gg][vv]) {
bb(xx,yy,gg,vv,st,wei);
wei++;
vis[xx][yy][gg][vv]=1;
}
}
continue;
}
if(mp[xx][yy]==3) {
vis[xx][yy][gg][vv]=1;
if(vv==0) continue;
bb(xx,yy,gg,vv,st,wei);
wei++;
/* for(int j=1;j<=p;j++)
if(xx==px[j]&&yy==py[j]) {
lox=j;
break;
}
for(int j=1;j<=p;j++) {
if(j!=lox) {
if(!vis[godx[j]][gody[j]][gg][vv-1]) {
bb(godx[j],gody[j],gg,vv-1,st,wei);
wei++;
vis[godx[j]][gody[j]][gg][vv-1]=1;
}
}
}*/
continue;
}
if(vis[xx][yy][gg][vv]==0) {
bb(xx,yy,gg,vv,st,wei);
wei++;
vis[xx][yy][gg][vv]=1;
}
}
head++;
}
// for(int i=1;i<=wei-1;i++) {
// cout<<bfs[i].x<<" "<<bfs[i].y<<" "<<bfs[i].g<<" "<<bfs[i].v<<" " << bfs[i].st<< endl;
// }
if(fa==0) {
printf("-1\n");
}
}
return 0;
}