题意
F--起点
S--空格
G--能量池,只能充一次电,充完之后G变为S,也可已选择不充而当成普通的S
D--激光区,不能走
Y--电源开关
M被关在一所监狱之中,F为起点,每走一步(上下左右)消耗1节能量,只要关闭完所有的Y就可以直接飞出去,可以到能量池里进行充电。问M要想出去所携带的电池的最小尺寸是多少。注意:能量池和开关的总和小于15。
思路
首先将图中所有的F,G,Y找出来,并用BFS求出这三种标志任意两者的距离。具体看例子
GDDSS
SSSFS
SYGYS
SGSYS
SSYSS
//经处理后变为
F--0: 1,3
Y--1: 2,1
Y--2: 2,3
Y--3: 3,3
Y--4: 4,2
G--5: 0,0
G--6: 2,2
G--7: 3,1//之所以要先F再Y再G是为了状压的时候只要考虑前5个点(0~4)都走过(即都变成1)时方便处理。
//经BFS后记录任意亮点的距离(无视充电池,但要考虑激光区)
0,0--0
0,1--3
0,2--1
0,3--2
0,4--4
0,5--4
0,6--2
0,7--4
1,0--3
1,1--0
1,2--2
1,3--3
1,4--3
1,5--3
1,6--1
1,7--1
2,0--1
2,1--2
2,2--0
2,3--1
2,4--3
2,5--5
2,6--1
2,7--3
3,0--2
3,1--3
3,2--1
3,3--0
3,4--2
3,5--6
3,6--2
3,7--2
4,0--4
4,1--3
4,2--3
4,3--2
4,4--0
4,5--6
4,6--2
4,7--2
5,0--4
5,1--3
5,2--5
5,3--6
5,4--6
5,5--0
5,6--4
5,7--4
6,0--2
6,1--1
6,2--1
6,3--2
6,4--2
6,5--4
6,6--0
6,7--2
7,0--4
7,1--1
7,2--3
7,3--2
7,4--2
7,5--4
7,6--2
7,7--0
状态转移方程要设一个辅助的dp用来存当前走了都少步,遇到能量池时步数变为0;dp_v用来存走到当前状态历史最大的步数 。//不好理解
dp[i+sta[j]][j]=dp[i][k]+g[k][j]; 或 dp[i+sta[j]][j]=0;
dp_v[i+sta[j][j]=max(dp[i+sta[j]][j],dp_v[i][k]);
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
int sta[20]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
int dp[32768][20];
int dp_v[32768][20];
int flag[32768][20];
int g[20][20];
char Map[20][20],c;
int N,M,ctor,nY;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
const int INF=0x7fffffff;
struct node
{
int x,y;
};
node a[20],temp;
struct tool
{
int num,step;
};
tool t[20][20];
//预处理
void import();
void init();
void BFS();
int main()
{
while(scanf("%d%d",&N,&M)&&N&&M)
{
init();
import();
BFS();
int ans=INF;
int ans1=INF;
int jud=sta[nY]-1;
int jx=sta[ctor]-1;
queue<node>q;
while(!q.empty()) q.pop();
temp.x=1;
temp.y=0;
dp[temp.x][temp.y]=0;
dp_v[temp.x][temp.y]=0;
flag[temp.x][temp.y]=0;
q.push(temp);
while(!q.empty())
{
int i=q.front().x;
int k=q.front().y;
q.pop();
flag[i][k]=1;
for(int j=0;j<ctor;++j)
{
if((sta[j]&i)==0&&g[k][j]!=-1)
{
temp.x=i+sta[j];
temp.y=j;
if(j<nY&&(dp_v[temp.x][temp.y]==-1||dp_v[temp.x][temp.y]>max(dp[i][k]+g[k][j],dp_v[i][k])))
{
dp[temp.x][temp.y]=dp[i][k]+g[k][j];
dp_v[temp.x][temp.y]=max(dp[temp.x][temp.y],dp_v[i][k]);
if((temp.x&jud)==jud)
{
ans=min(ans,dp_v[temp.x][temp.y]);
}
else if(temp.x<jx&&flag[temp.x][temp.y])
{
q.push(temp);
flag[temp.x][temp.y]=0;
}
}
if(j>=nY&&(dp_v[temp.x][temp.y]==-1||dp_v[temp.x][temp.y]>max(dp[i][k]+g[k][j],dp_v[i][k])))
{
dp[temp.x][temp.y]=0;
dp_v[temp.x][temp.y]=max(dp[i][k]+g[k][j],dp_v[i][k]);
if(temp.x<jx&&flag[temp.x][temp.y])
{
q.push(temp);
flag[temp.x][temp.y]=0;
}
}
}
}
}
if(N==1&&M==1)
printf("0\n");
else if(ans==INF)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}
void init()
{
memset(g,-1,sizeof(g));
memset(flag,-1,sizeof(flag));
memset(dp,-1,sizeof(dp));
memset(dp_v,-1,sizeof(dp));
for(int i=0;i<N;++i)
{
for(int j=0;j<M;++j)
{
t[i][j].num=-1;
t[i][j].step=-1;
}
}
}
void BFS()
{
for(int i=0;i<ctor;++i)
{
for(int I=0;I<N;++I) for(int J=0;J<M;++J) t[I][J].step=-1;
queue<node>q;
temp.x=a[i].x;
temp.y=a[i].y;
t[temp.x][temp.y].step=0;
q.push(temp);
while(!q.empty())
{
int x=q.front().x;
int y=q.front().y;
q.pop();
for(int j=0;j<4;++j)
{
temp.x=x+dx[j];
temp.y=y+dy[j];
if(temp.x>=0&&temp.x<N&&temp.y>=0&&temp.y<M&&Map[temp.x][temp.y]!='D'&&(t[temp.x][temp.y].step==-1||t[temp.x][temp.y].step>t[x][y].step+1))
{
t[temp.x][temp.y].step=t[x][y].step+1;
q.push(temp);
}
}
}
for(int I=0;I<N;++I)
{
for(int J=0;J<M;++J)
{
int j=t[I][J].num;
if(j!=-1)
{
g[i][j]=t[I][J].step;
}
}
}
}
}
void import()
{
for(int i=0;i<N;++i)
{
for(int j=0;j<M;++j)
{
cin>>c;
Map[i][j]=c;
}
}
ctor=0;
for(int i=0;i<N;++i)
{
for(int j=0;j<M;++j)
{
if(Map[i][j]=='F')
{
a[ctor].x=i;
a[ctor].y=j;
t[i][j].num=ctor;
++ctor;
}
}
}
for(int i=0;i<N;++i)
{
for(int j=0;j<M;++j)
{
if(Map[i][j]=='Y')
{
a[ctor].x=i;
a[ctor].y=j;
t[i][j].num=ctor;
++ctor;
}
}
}
nY=ctor;
for(int i=0;i<N;++i)
{
for(int j=0;j<M;++j)
{
if(Map[i][j]=='G')
{
a[ctor].x=i;
a[ctor].y=j;
t[i][j].num=ctor;
++ctor;
}
}
}
}
---恢复内容结束---