题意:一幅矩阵迷宫,給起点,开始时充满电,要求是遍历给定的点,每移动一次花费1,
迷宫中有若干充电池可充满电(每个充电池只能用一次),求原始电量最少是多少。
分析:
1、由于所有‘Y‘处一定要走到,‘G‘可以走也可以不走,且他们的总个数最多只有15个。
the sum of energy pools and power switches is less than 15.
因此可以用状态压缩思想记录最终的状态。
因此要给这些符号所在的位置编号。 用hash思想把图中各符号的位置用横纵坐标唯一表示。
即posid=x*列数+y。
2、重新建图,把能走的点之间建边,然后bfs出图中任意两个点之间的最短距离。
3、二分枚举原始电量,找到最小值。
验证能否达到末态的过程中,如果要走的点为‘G‘,则电量为原始的满电量,否则为这一步的起点
位置电量 - 起点到终点的最短距离。
bfs+dfs
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<algorithm> using namespace std; struct edge { int to,next; }e[2000]; struct node { int vid,step; }; char mp[20][20]; int id[20][20],c[20][2],head[300],dis[20][20]; int cnt,obj,ids,mid,m,n; bool mk[20]; void init() { memset(id,-1,sizeof(id)); memset(dis,-1,sizeof(dis)); memset(head,-1,sizeof(head)); cnt=0;ids=1;obj=0; } void add(int x,int y) { e[cnt].to=y; e[cnt].next=head[x]; head[x]=cnt++; } void bfs(int x) { int u,v; node djw,cur,next; queue<node> q; bool vis[400]; memset(vis,0,sizeof(vis)); djw.vid=x; djw.step=0; q.push(djw); vis[x]=true; while(!q.empty()) { cur=q.front(); q.pop(); u=cur.vid; if(id[u/m][u%m]!=-1) dis[id[x/m][x%m]][id[u/m][u%m]]=cur.step; for(int i=head[u];i!=-1;i=e[i].next) { v=e[i].to; if(!vis[v]) { vis[v]=true; next.vid=v; next.step=cur.step+1; q.push(next); } } } } int dfs(int bag,int pos,int sta) { if((sta&obj)==obj) return 1; for(int i=0;i<ids;i++) { if(mk[i] || dis[pos][i]==-1) continue; if(dis[pos][i]<=bag) { if(mp[c[i][0]][c[i][1]]==‘G‘) { mk[i]=true; if(dfs(mid,i,sta|(1<<i))) return 1; mk[i]=false; } else { mk[i]=true; if(dfs(bag-dis[pos][i],i,sta|(1<<i))) return 1; mk[i]=false; } } } return 0; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { if(n==0 && m==0) break; init(); for(int i=0;i<n;i++) scanf("%s",mp[i]); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(mp[i][j]==‘D‘) continue; if(mp[i][j]==‘F‘) { c[0][0]=i; c[0][1]=j; id[i][j]=0; } else if(mp[i][j]==‘G‘) { c[ids][0]=i; c[ids][1]=j; id[i][j]=ids++; } else if(mp[i][j]==‘Y‘) { c[ids][0]=i; c[ids][1]=j; obj|=(1<<ids); id[i][j]=ids++; } if(i-1>=0 && mp[i-1][j]!=‘D‘) add(i*m+j,(i-1)*m+j); if(i+1<n && mp[i+1][j]!=‘D‘) add(i*m+j,(i+1)*m+j); if(j-1>=0 && mp[i][j-1]!=‘D‘) add(i*m+j,i*m+j-1); if(j+1<m && mp[i][j+1]!=‘D‘) add(i*m+j,i*m+j+1); } } for(int i=0;i<ids;i++) bfs(c[i][0]*m+c[i][1]); int flag=1; for(int i=1;i<ids;i++) { if(mp[c[i][0]][c[i][1]]==‘Y‘ && dis[0][i]==-1) { flag=0; break; } } int ans=-1; if(flag) { int l=0,r=n*m*(ids-1); while(l<=r) { mid=(l+r)>>1; memset(mk,0,sizeof(mk)); mk[0]=true; if(dfs(mid,0,1)) { ans=mid; r=mid-1; } else l=mid+1; } } printf("%d\n",ans); } return 0; }
dp+bfs
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<algorithm> using namespace std; struct edge { int to,next; }e[2000]; struct node { int vid,step; }; char mp[20][20]; int id[20][20],c[20][2],head[300],dis[20][20]; int dp[1<<16][16]; int cnt,obj,ids,mid,m,n; void init() { memset(id,-1,sizeof(id)); memset(dis,-1,sizeof(dis)); memset(head,-1,sizeof(head)); cnt=0;ids=1;obj=0; } void add(int x,int y) { e[cnt].to=y; e[cnt].next=head[x]; head[x]=cnt++; } void bfs(int x) { int u,v; node djw,cur,next; queue<node> q; bool vis[400]; memset(vis,0,sizeof(vis)); djw.vid=x; djw.step=0; q.push(djw); vis[x]=true; while(!q.empty()) { cur=q.front(); q.pop(); u=cur.vid; if(id[u/m][u%m]!=-1) dis[id[x/m][x%m]][id[u/m][u%m]]=cur.step; for(int i=head[u];i!=-1;i=e[i].next) { v=e[i].to; if(!vis[v]) { vis[v]=true; next.vid=v; next.step=cur.step+1; q.push(next); } } } } int solve(int mid) { memset(dp,-1,sizeof(dp)); dp[1][0]=mid; for(int i=0;i<(1<<ids);i++) { for(int j=0;j<ids;j++) { if((i&(1<<j)==0) || dp[i][j]==-1) continue; if((i&obj)==obj) return 1; for(int k=0;k<ids;k++) { if(j==k || i&(1<<k)) continue; if(dis[j][k]==-1) continue; if(dp[i][j]>=dis[j][k]) { if(dp[i|(1<<k)][k]==-1 || dp[i|(1<<k)][k]<dp[i][j]-dis[j][k]) dp[i|(1<<k)][k]=dp[i][j]-dis[j][k]; if(mp[c[k][0]][c[k][1]]==‘G‘) dp[i|(1<<k)][k]=mid; } } } } return 0; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { if(n==0 && m==0) break; init(); for(int i=0;i<n;i++) scanf("%s",mp[i]); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(mp[i][j]==‘D‘) continue; if(mp[i][j]==‘F‘) { c[0][0]=i; c[0][1]=j; id[i][j]=0; } else if(mp[i][j]==‘G‘) { c[ids][0]=i; c[ids][1]=j; id[i][j]=ids++; } else if(mp[i][j]==‘Y‘) { c[ids][0]=i; c[ids][1]=j; id[i][j]=ids++; obj|=(1<<(ids-1)); } if(i-1>=0 && mp[i-1][j]!=‘D‘) add(i*m+j,(i-1)*m+j); if(i+1<n && mp[i+1][j]!=‘D‘) add(i*m+j,(i+1)*m+j); if(j-1>=0 && mp[i][j-1]!=‘D‘) add(i*m+j,i*m+j-1); if(j+1<m && mp[i][j+1]!=‘D‘) add(i*m+j,i*m+j+1); } } for(int i=0;i<ids;i++) bfs(c[i][0]*m+c[i][1]); int ans=-1; int l=0,r=n*m*(ids-1); while(l<=r) { mid=(l+r)>>1; if(solve(mid)) { ans=mid; r=mid-1; } else l=mid+1; } printf("%d\n",ans); } return 0; }