您的位置:首页 > 其它

HDU_4856_Tunnels(BFS+状态压缩)

2014-07-15 09:15 316 查看
题型:搜索+DP

题意:

N*N的地图中,‘#’代表障碍物,‘.’代表可走。地图上有M条隧道的入口和出口,隧道是有向的。起始时可以选择地图上任意一个可走的点作为起点,在隧道中行走不算时间。问最少要多少时间可以把所有隧道走完。

分析:

在做西安邀请赛重现的时候,在这题上遇到的麻烦,主要还是怪自己太捉急,尝试了网络流和SPFA或者直接搜等各种无厘头的想法,但是都搞错的方向。

首先,在起点的选择上,一定是要选择某一条隧道的入口的,其实也是出口,因为过隧道不花时间。所以,花时间的地方就在地图上,即从某一个隧道的终点到另一个隧道的起点的距离,因此,要先BFS找出每一个隧道的终点到其他每一个隧道的起点的距离。

如何找出将所有隧道都走完的最短时间呢?

采用状态压缩,二进制枚举所有的隧道的使用情况,为了避免冲突,还要再加一维。表示当前状态的上一个状态的隧道。

设dp[i][j]表示从j隧道而来,且所走过的隧道为 i (i是二进制串)状态下的最短路程。

枚举1<<15中的所有状态,从当前状态推导出下一状态的所有情况并更新。

最终答案为min{dp[(1<<M)-1][i]}(i from 1 to m)。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#define INF 0x3f3f3f3f
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;

int n,m;

char Map[20][20];
bool vis[20][20];
int dist[20][20];

int dp[50000][20];

struct POINT {
int x,y;
} start[20],end[20];

struct Node {
int x,y;
int step;
};

int dir1[] = {0,0,1,-1};
int dir2[] = {1,-1,0,0};

bool check(Node vw) {
if(vw.x>=0&&vw.x<n && vw.y>=0&&vw.y<n && !vis[vw.x][vw.y] && Map[vw.x][vw.y]!='#')
return true;
else return false;
}

int BFS(POINT S,POINT E) {
mt(vis,false);
queue<Node> q;
Node now;
now.x = S.x;
now.y = S.y;
now.step = 0;
q.push(now);
vis[now.x][now.y] = true;
while(!q.empty()) {
now = q.front();
q.pop();
if(now.x==E.x && now.y==E.y) return now.step;
for(int i=0; i<4; i++) {
Node vw;
vw.x = now.x + dir1[i];
vw.y = now.y + dir2[i];
vw.step = now.step +1 ;
if(check(vw)) {
q.push(vw);
vis[vw.x][vw.y] = true;
}
}
}
return -1;
}

int main() {
while(~scanf("%d%d",&n,&m)) {
for(int i=0; i<n; i++) {
scanf("%s",Map[i]);
}
for(int i=0; i<m; i++) {
scanf("%d%d%d%d",&start[i].x,&start[i].y,&end[i].x,&end[i].y);
start[i].x--;
start[i].y--;
end[i].x--;
end[i].y--;
}

mt(dist,0);
for(int i=0; i<m; i++) {
for(int j=0; j<m; j++) {
if(i==j) {
dist[i][j] = 0;
continue;
}
dist[i][j] = BFS(end[i],start[j]);
if(dist[i][j] == -1) dist[i][j] = INF;
}
}

//        for(int i=0;i<m;i++){
//            for(int j=0;j<m;j++){
//                printf("%5d ",dist[i][j]);
//            }
//            puts("");
//        }

mt(dp,INF);

for(int i=0; i<m; i++) {
dp[1<<i][i] = 0;
}

int big = (1<<m);

for(int i=0; i<big; i++) {
int tmp = i;

for(int pos=0; pos<m; pos++) {
if(!(tmp&1)) {
for(int j=0; j<m; j++) {
if((i>>j)&1) {
dp[i|(1<<pos)][pos] = min(dp[i|(1<<pos)][pos],dp[i][j]+dist[j][pos]);
}
}
}

tmp >>= 1;
}

}

int ans = INF;
for(int i=0; i<m; i++) {
ans = min(ans,dp[(1<<m)-1][i]);
}
if(ans == INF) ans = -1;
printf("%d\n",ans);

}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: