您的位置:首页 > 其它

HDU-4856 Tunnels(BFS&&状压DP)

2016-05-02 17:32 465 查看


Tunnels

http://acm.hdu.edu.cn/showproblem.php?pid=4856

Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)



Problem Description

Bob is travelling in Xi’an. He finds many secret tunnels beneath the city. In his eyes, the city is a grid. He can’t enter a grid with a barrier. In one minute, he can move into an adjacent grid with no barrier. Bob is full of curiosity and he wants to visit
all of the secret tunnels beneath the city. To travel in a tunnel, he has to walk to the entrance of the tunnel and go out from the exit after a fabulous visit. He can choose where he starts and he will travel each of the tunnels once and only once. Now he
wants to know, how long it will take him to visit all the tunnels (excluding the time when he is in the tunnels).

Input

The input contains mutiple testcases. Please process till EOF.

For each testcase, the first line contains two integers N (1 ≤ N ≤ 15), the side length of the square map and M (1 ≤ M ≤ 15), the number of tunnels.

The map of the city is given in the next N lines. Each line contains exactly N characters. Barrier is represented by “#” and empty grid is represented by “.”.

Then M lines follow. Each line consists of four integers x1, y1, x2, y2, indicating there is a tunnel with entrence in (x1, y1) and exit in (x2, y2). It’s guaranteed that
(x1, y1) and (x2, y2) in the map are both empty grid.

Output

For each case, output a integer indicating the minimal time Bob will use in total to walk between tunnels.

If it is impossible for Bob to visit all the tunnels, output -1.

Sample Input

5 4
....#
...#.
.....
.....
.....
2 3 1 4
1 2 3 5
2 3 3 1
5 4 2 1


Sample Output

7


题目大意:给定一个n*n的格子,'.'代表可以走,'#'代表不可以走,每分钟可以往相邻的格子走,又存起点和终点已知的m条隧道,可以从任意一点开始,求经过所有隧道所用的最短时间?

大致思路:先bfs预处理出任意两点的最短路,然后就转换为TSP问题,由于必经的隧道很小,所以可以用状压DP

设dp[i][j]表示当前i中二进制中为1的位已经走过,且最后一个走过的隧道为第j条隧道

【注意】必须把表示走过的某些隧道这个状态放在最外层,把隧道放在最内层,WA在这2.5h,还是不太熟悉状压DP

只有这样才能保证当前使用的状态是最优状态,否则就限定了部分遍历隧道的顺序

①若未遍历的隧道在最外层,则限定了最后一个必定经过第m-1条隧道

②若已遍历的隧道在最外层,则限定了倒数第二个必定经过第m-1条隧道

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

struct Node {
int r,c,t;

Node(int rr=0,int cc=0,int tt=0):r(rr),c(cc),t(tt) {}
}u;

struct Tunnel {
int sr,sc,er,ec;
}tun[17];

char city[17][17];
int n,m,rr,cc,mx;
int time[17][17][17][17];
bool vis[17][17];
int dp[(1<<15)+5][17];

const int dr[4]={-1,0,1,0};
const int dc[4]={0,1,0,-1};

inline bool isInside(int r,int c) {
return 1<=r&&r<=n&&1<=c&&c<=n;
}

void bfs(int r,int c) {
queue<Node> q;
q.push(Node(r,c,0));
memset(vis,false,sizeof(vis));
vis[r][c]=true;
while(!q.empty()) {
u=q.front();
q.pop();
time[r][c][u.r][u.c]=u.t;
for(int i=0;i<4;++i) {
rr=u.r+dr[i];
cc=u.c+dc[i];
if(isInside(rr,cc)&&city[rr][cc]!='#'&&!vis[rr][cc]) {
vis[rr][cc]=true;
q.push(Node(rr,cc,u.t+1));
}
}
}
}

int main() {
while(2==scanf("%d%d",&n,&m)) {
mx=1<<m;
for(int i=1;i<=n;++i) {
scanf("%s",&city[i][1]);
}
memset(time,0x3f,sizeof(time));
memset(dp,0x3f,sizeof(dp));
for(int i=0;i<m;++i) {
scanf("%d%d%d%d",&tun[i].sr,&tun[i].sc,&tun[i].er,&tun[i].ec);
bfs(tun[i].er,tun[i].ec);
dp[1<<i][i]=0;
}
for(int j=0;j<mx;++j) {
for(int i=0;i<m;++i) {
if((j&(1<<i))==0) {//如果当前状态的第i条隧道未走过
for(int k=0;k<m;++k) {
if(dp[j][k]!=0x3f3f3f3f) {//如果当前状态的第k条隧道已走过
dp[j|(1<<i)][i]=min(dp[j|(1<<i)][i],dp[j][k]+time[tun[k].er][tun[k].ec][tun[i].sr][tun[i].sc]);
}
}
}
}
}
int ans=0x3f3f3f3f;
for(int i=0;i<m;++i) {
ans=min(ans,dp[mx-1][i]);
}
printf("%d\n",ans==0x3f3f3f3f?-1:ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: