1. 程式人生 > >QDUOJ 來自xjy的簽到題(bfs+狀壓dp)

QDUOJ 來自xjy的簽到題(bfs+狀壓dp)

max 狀壓dp str container sizeof print char bfs 現在

來自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;
}

QDUOJ 來自xjy的簽到題(bfs+狀壓dp)