题意:一个n*n的网格,"#"表示障碍物,m个隧道,每个隧道都有个出口和入口,为走遍所有隧道的最短时间,一分钟走一个网格。绝对是到好题,N很少,一开始用bfs+dfs做,超时了,因为dfs时的时间复杂度是15!。
解题思路:把模型转换一下就变成了,n个隧道,每个隧道之间的距离为c[i][j](这个是通过bfs求出来的),然后就用状态压缩DP解,dp[i][j]表示当前状态为i所在的隧道是j,
状态转移dp[(1<<k)+j][k] = min(dp[(1<<k)+j][k],c[i][j]+dp[i][j]),然后初始化dp为inf,dp[1<<i][i] = 0。到这里题目就可以做出来了
代码如下:
#include<iostream> #include<algorithm> #include<queue> #include<stdio.h> #include<math.h> #include<cstring> #include<string> #define N 20 #define inf 0x3f3f3f3f #define pi acos(-1.0) #define eps 10e-6 using namespace std; char a[N][N]; struct node { int x,y; }s[N],e[N]; int dp[1<<16][N]; queue<node> q; int vis[N][N]; int tag[N]; int n,m,ans,flag; int c[N][N]; int dist[N][N]; int d[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; void bfs(int x,int y)//求每个隧道出口到其他隧道入口的最近距离 { for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) dist[i][j] = inf; memset(vis,0,sizeof(vis)); while(!q.empty()) q.pop(); node temp; temp.x = x; temp.y = y; q.push(temp); vis[x][y] = 1; dist[x][y] = 0; while(!q.empty()) { node now = q.front(); q.pop(); int i; for(i = 0; i < 4; i++) { int tempx = now.x + d[i][0]; int tempy = now.y + d[i][1]; temp.x = tempx; temp.y = tempy; if(tempx < 0 || tempx >= n || tempy < 0 || tempy >= n || vis[tempx][tempy] || a[tempx][tempy] == '#') continue; vis[tempx][tempy] = 1; dist[tempx][tempy] = dist[now.x][now.y]+1; q.push(temp); } } } int main() { while(scanf("%d%d",&n,&m) != EOF) { int i, j,k; for(i = 0; i < n; i++) scanf("%s",a[i]); for(i = 0; i < m; i++){ scanf("%d%d%d%d",&s[i].x,&s[i].y,&e[i].x,&e[i].y); s[i].x--;s[i].y--;e[i].x--;e[i].y--; } memset(c,0,sizeof(c)); for(i = 0; i < m; i++) { bfs(e[i].x,e[i].y); for(j = 0; j < m; j++) if(i != j) c[i][j] = dist[s[j].x][s[j].y]; } for(i = 0; i < (1<<m); i++) for(j = 0; j < m; j++) dp[i][j] = inf;//注意初始化 for(i = 0; i < m; i++) dp[1<<i][i] = 0; for(i = 0; i < (1<<m); i++)//关键在这里 for(j = 0; j < m; j++) if(i&(1<<j)) for(k = 0; k < m; k++) { if(k == j) continue; if((i&(1<<k)) == 0) dp[i+(1<<k)][k] = min(dp[i+(1<<k)][k],c[j][k]+dp[i][j]); } int ans = inf; for(i = 0; i < m; i++) if(dp[(1<<m)-1][i] < ans) ans = dp[(1<<m)-1][i]; if(ans >= inf) printf("-1\n"); else printf("%d\n",ans); } return 0; }