QDUOJ 来自xjy的签到题(bfs+状压dp)

来自xjy的签到题
 

Description

 

爱丽丝冒险来到了红皇后一个n*n大小的花园,每个格子由'.'或'#'表示,'.'表示爱丽丝可以到达这个格子,‘#’表示爱丽丝不能到达这个格子,爱丽丝每1分钟可以移动到非'#'的相邻格子(与当前所在格子具有公共边)。花园下面有m个隧道,每个隧道有一个出口和一个入口。当爱丽丝到达隧道的入口时,她可以选择(也可以不选择)进入隧道入口,并通过隧道一次,然后立即(不花费时间)出现在隧道出口。爱丽丝一开始可以降临在花园的任何地方。有好奇心的爱丽丝想知道,她通过所有隧道且每个隧道仅通过一次最少需要花费多少时间。(注意,爱丽丝不能从隧道出口通往隧道入口)

 

Input

 

输入包含多个测试用例,不超过10组。对于每个测试用例,第一行输入n(1<=n<=15)和m(1<=m<=15),分别表示地图的大小为n*n和m个隧道。然后给出一个n行n列的花园地图,由'.'或'#'组成,'.'表示爱丽丝可以到达这个格子,‘#’表示爱丽丝不能到达这个格子。接下来m行,表示m个隧道。每行四个正整数x1,y1,x2,y2(1<=x1,x2,y1,y2<=15),表示隧道的入口为(x1,y1),出口为(x2,y2)。数据保证隧道入口和出口位置不会出现在‘#’上。

 

Output

 

对于每个测试用例,你需要输出一个整数,表示爱丽丝通过所有隧道仅一次的最少时间。如果爱丽丝无法通过所有隧道,则输出-1。

 

Sample Input 1 

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

Sample Output 1

7

Hint

对于样例,爱丽丝可以一开始降临在(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;
}

 

posted @ 2018-08-31 21:37  yzm10  阅读(210)  评论(0编辑  收藏  举报