题意
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; } } } }
---恢复内容结束---