题意:一个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;
}