对于样例,爱丽丝可以一开始降临在(2,3)并穿过第一个隧道到达(1,4),然后花费2分钟走向(1,2)并穿过第二个隧道到达(3,5),然后花费3分钟走向(5,4)并穿过第四个隧道到达(2,1),最后花费2分钟走向(2,3)并穿过第三个隧道到达(3,1)。至此通过所有隧道,并花费7分钟时间。
注意本题时间限制和空间限制
将隧道视为点,先bfs预处理出两两隧道间的距离,然后使用状压dp求出最小时间。
转移方程:dp[目标状态][目标点]=min(dp[目标状态][目标点],dp[当前状态][当前点]+dis[当前点][目标点])。
#include<bits/stdc++.h> #define MAX 16 #define INF 0x3f3f3f3f using namespace std; char s[MAX][MAX]; int b[MAX][MAX],dis[MAX][MAX]; int dp[1<<15][MAX]; int t[4][2]={1,0,0,1,-1,0,0,-1}; struct Node{ int bx,by,ex,ey; }a[MAX]; struct Node2{ int x,y,s; }node; queue<Node2> q; int bfs(Node u,Node v,int n){ memset(b,0,sizeof(b)); while(q.size()){ q.pop(); } if(u.ex==v.bx&&u.ey==v.by) return 0; node.x=u.ex; node.y=u.ey; node.s=0; q.push(node); b[node.x][node.y]=1; while(q.size()){ for(int i=0;i<4;i++){ Node2 now=q.front(); int tx=now.x+t[i][0]; int ty=now.y+t[i][1]; if(tx<1||tx>n||ty<1||ty>n) continue; if(s[tx][ty]==‘#‘||b[tx][ty]==1) continue; b[tx][ty]=1; if(tx==v.bx&&ty==v.by){ return now.s+1; } node.x=tx; node.y=ty; node.s=now.s+1; q.push(node); } q.pop(); } return INF; } int main() { int n,m,i,j,k; while(~scanf("%d%d",&n,&m)){ for(i=1;i<=n;i++){ scanf(" %s",s[i]+1); } for(i=1;i<=m;i++){ scanf("%d%d%d%d",&a[i].bx,&a[i].by,&a[i].ex,&a[i].ey); } memset(dis,INF,sizeof(dis)); for(i=1;i<=m;i++){ for(j=1;j<=m;j++){ if(i==j) continue; dis[i][j]=bfs(a[i],a[j],n); } } memset(dp,INF,sizeof(dp)); for(i=1;i<=m;i++){ dp[1<<(i-1)][i]=0; } for(i=0;i<(1<<m);i++){ for(j=1;j<=m;j++){ if(!(i&(1<<(j-1)))) continue; for(k=1;k<=m;k++){ if(j==k||dis[j][k]==INF||!(i&(1<<(k-1)))) continue; dp[i][k]=min(dp[i][k],dp[i^(1<<(k-1))][j]+dis[j][k]); } } } int ans=INF; for(i=1;i<=m;i++){ ans=min(ans,dp[(1<<m)-1][i]); } if(ans==INF) printf("-1\n"); else printf("%d\n",ans); } return 0; }