思路:先BFS出关键点(起点,电池,开关)之间的最短路
然后状态压缩DP dp[当前位置][状态]=电池电量
二分答案即可
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <queue> using namespace std; const int N=16; #define for if(0); else for struct Point{ int x,y; Point(){x=y=0;} Point(int xx,int yy){x=xx;y=yy;} }; const int inf=0x0f0f0f0f; int n,m; Point que[N*N+100]; int vis[N][N]; int d[N][N]; int td[N][N]; char g[N][N]; int no[N][N]; Point P[N]; int nG,nY,num; void bfs(int s,int d[],int td[][N]){ for(int i=0;i<N;i++) d[i]=inf; d[s]=0; memset(vis,0,sizeof(vis)); memset(td,0x0f,N*N*sizeof(int)); int st=0,ed=0; int dx[4]={0,0,1,-1}; int dy[4]={1,-1,0,0}; que[ed++]=P[s]; td[P[s].x][P[s].y]=0; vis[P[s].x][P[s].y]=1; while(st!=ed){ Point cur=que[st++]; int curdis=td[cur.x][cur.y]; if(no[cur.x][cur.y]!=-1){ d[no[cur.x][cur.y]]=curdis; } for(int i=0;i<4;i++){ Point np=Point(cur.x+dx[i],cur.y+dy[i]); if(!vis[np.x][np.y] && g[np.x][np.y]!='D' && g[np.x][np.y]!=0){ vis[np.x][np.y]=1; td[np.x][np.y]=curdis+1; que[ed++]=np; } } } } int dp[15][1<<15]; bool can(int maxbatt){ int maxmask=1<<(num-1); int sta=maxmask-1; for(int i=0;i<num;i++) memset(dp[i],-1,maxmask*sizeof(int)); dp[0][sta]=maxbatt; for(int stat=sta;stat>=0;stat--){ for(int i=1;i<num;i++){ int mm=1<<(i-1); for(int j=0;j<num;j++) if(j!=i) { int cost=d[i][j]; if(dp[j][stat]-cost>=0) dp[i][stat]=max(dp[i][stat],dp[j][stat]-cost); if(~stat&mm){ int prev=stat^mm; if(i<=nG) { if(dp[j][prev]-cost>=0) { dp[i][stat]=maxbatt; } }else{ if(dp[j][prev]-cost>=0) dp[i][stat]=max(dp[i][stat],dp[j][prev]-cost); } } } if(stat<(1<<nG) && dp[i][stat]>=0) return true; } } return false; } int main() { while(scanf("%d%d",&n,&m)&&(n||m)){ memset(g,0,sizeof(g)); for(int i=1;i<=n;i++) scanf("%s",g[i]+1); nG=nY=num=0; memset(no,-1,sizeof(no)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(g[i][j]=='F') P[num]=Point(i,j),no[i][j]=num++; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(g[i][j]=='G') P[num]=Point(i,j),nG++,no[i][j]=num++; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(g[i][j]=='Y') P[num]=Point(i,j),nY++,no[i][j]=num++; for(int i=0;i<num;i++){ bfs(i,d[i],td); } bool haveans=true; for(int i=nG+1;i<num;i++) if(d[0][i]==inf) haveans=false; int left=0,right=n*m; int mid,ans=-1; if(haveans){ while(left<=right){ mid=(left+right)>>1; if(can(mid)){ ans=mid; right=mid-1; }else left=mid+1; } } if(nY==0) ans=0; printf("%d\n",ans); } return 0; }