QDUOJ 來自xjy的簽到題(bfs+狀壓dp)
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)