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

原文地址:https://www.cnblogs.com/yzm10/p/9568363.html

时间: 2024-08-02 02:44:41

QDUOJ 来自xjy的签到题(bfs+状压dp)的相关文章

[luoguP3694] 邦邦的大合唱站队/签到题(状压DP)

传送门 来自kkk的题解: 70分做法:枚举每个学校顺序,暴力. 100分:状压dp.从队列头到尾DP, 状态:f[i]表示i状态下最小的出列(不一致)的个数. 比如f[1101]表示从头到位为1/3/4乐队的偶像的最小出列个数. f[i]=min(f[i\ xor\ 2^j]+num[j]-(sum[length][j]-sum[length-num[j]][j]));f[i]=min(f[i xor 2?j??]+num[j]−(sum[length][j]−sum[length−num[j

HDU 4856 Tunnels(BFS+状压DP)

HDU 4856 Tunnels 题目链接 题意:给定一些管道,然后管道之间走是不用时间的,陆地上有障碍,陆地上走一步花费时间1,求遍历所有管道需要的最短时间,每个管道只能走一次 思路:先BFS预处理出两两管道的距离,然后状态压缩DP求解,dp[s][i]表示状态s,停在管道i时候的最小花费 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using

HDU-3502-Huson&#39;s Adventure Island(BFS+状压DP)

Problem Description A few days ago, Tom was tired of all the PC-games, so he went back to some old FC-games. "Hudson's Adventure Island" was his favorite which he had played thousands of times. But to his disappointed, the more he played, the mo

Orz_panda cup I题 (xdoj1117) 状压dp

Orz_panda cup I题 (xdoj1117)  状压dp 1117: Insert Orz Pandas 时间限制: 2 Sec  内存限制: 128 MB提交: 15  解决: 5[提交][状态][讨论版] 题目描述 Orz panda emotion is a famous emotion in XDU/ACM-ICPC QQ groups.Big Big Xi loves to create new Orz panda emotions.Now he has a matrix w

HDU-4856 Tunnels (BFS+状压DP)

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 cur

POJ 2688 BFS+状压DP

标准的TSP问题 m*n矩阵,有不超过10个需要走到的点,给出起点,问走最少的步子把所有点走完 BFS出每个必须走到的点的最短距离 然后状压DP即可 #include "stdio.h" #include "string.h" #include "queue" using namespace std; const int dir[4][2]={ {1,0},{-1,0},{0,1},{0,-1} }; int inf=0x7fffffff; in

HDU-3681-Prison Break(BFS+状压DP+二分)

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one day, the king of Rompire was captured by human beings. His thinking circuit was changed by human and thus became a tyrant. All those who are against him

HDU 3681 BFS&amp;状压DP&amp;二分

N*M矩阵,从F点出发,走完所有的Y点,每走一格花费1点电量,走到G点时,电量充满,D不可到达,问起始时的最小满电量可以走完所有Y,Y和G一共最多15个 先BFS出所有的F,Y,G之间的最短距离. 然后二分起始电量,对每个电量,做状压DP判断是否可行 #include "stdio.h" #include "string.h" #include "queue" using namespace std; int inf=0x3f3f3f3f; in

【专业找水题】状压dp最水题,没有之一

题目链接 现在代码能力没上升,倒是越来越会找水题了(比例题还水的裸题你值得拥有) 这网站不是针对竞赛的,所以时空限制都很宽松 然后就让我水过去了 对于每个点,包括自己的前m个元素是否取都是一种状态,所以状压一下(才1024不要怂) 1 #include <cstdio> 2 int n,m,q; 3 int a[1001]; 4 int dp[1001][2000]; 5 int max(int a,int b){return(a<b)?b:a;} 6 int main() 7 { 8