[二分][记搜]JZOJ 3522 迷宫花园

Posted mastervan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[二分][记搜]JZOJ 3522 迷宫花园相关的知识,希望对你有一定的参考价值。

Description

给定一个一定存在从起点到终点的路径的四联通迷宫。已知Tar左右方向移动的时间为1,上下移动的时间为未知实数v。求当Tar从起点到终点的最短移动时间为已知实数L时,未知实数v是多少。
 

Input

输入数据包含多个测试点。第一行为一个整数T,表示测试点的数目。

对于每一个测试点,第一行包含实数L和两个整数R,C。R为迷宫的上下长度,C为迷宫的左右长度。

之后的R行,每行包含C个字符。其中空格表示空地,S表示起点,E表示终点,#表示围墙。

Output

对于每一个测试点,在单独的一行内输出未知实数v,输出保留5位小数。
 

Sample Input

2                                 
2.5 4 5                           
#####
#S  #
#  E#
#####
21 13 12
############
#S##     #E#
# ##  #  # #
#   # #  # #
### # #  # #
#   # #  # #
#  ## #  # #
##  # #  # #
### # #  # #
##  # #  # #
#  ## #    #
#     #    #
############

Sample Output

0.50000
0.21053
 

Data Constraint

20%的数据,1≤ R,C ≤ 10。

100%的数据,1≤ R,C ≤ 100,0≤ v <10。

分析

二分+记忆化搜索,注意BFS中已在队列中的不要反复加入,会T

 

技术分享图片
#include <iostream>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
const int N=110;
struct Point {
    int x,y;
}s,e;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
double f[N][N];
char ch[N][N];
int t,r,c;
double l,v;
bool inqueue[N][N];

double Cost(Point a,Point b) {
    if (abs(a.y-b.y)==1) return 1.0;
    else return v;
}

bool Judge(Point a,Point b) {
    if (b.x<1||b.x>r||b.y<1||b.y>c) return 0;
    if (ch[b.x][b.y]==#) return 0;
    if (f[a.x][a.y]+Cost(a,b)>f[b.x][b.y]) return 0;
    return 1;
}

void Bfs()  {
    queue<Point> q;
    while (!q.empty()) q.pop();
    for (int i=1;i<=r;i++)
        for (int j=1;j<=c;j++)
            f[i][j]=2147483647.0;
    q.push(s);f[s.x][s.y]=0;inqueue[s.x][s.y]=1;
    while (!q.empty()) {
        Point p=q.front();q.pop();
        for (int i=0;i<4;i++)
            if (Judge(p,(Point){p.x+dx[i],p.y+dy[i]})) {
                Point to=(Point){p.x+dx[i],p.y+dy[i]};
                f[to.x][to.y]=f[p.x][p.y]+Cost(p,to);
                if (!inqueue[to.x][to.y]) q.push(to);
                inqueue[to.x][to.y]=1;
            }
        inqueue[p.x][p.y]=0;
    }
}

int main() {
    freopen("maze.in","r",stdin);
    freopen("maze.out","w",stdout);
    scanf("%d",&t);
    for (;t;t--) {
        scanf("%lf%d%d",&l,&r,&c);
        for (int i=1;i<=r;i++)
            for (int j=1;j<=c;j++) {
                do {
                    scanf("%c",&ch[i][j]);
                }
                while (ch[i][j]!=#&&ch[i][j]!=E&&ch[i][j]!=S&&ch[i][j]!= );
                if (ch[i][j]==E) e.x=i,e.y=j;
                if (ch[i][j]==S) s.x=i,s.y=j;
            }
        double ll=1e-7,rr=10.0;
        while (rr-ll>=1e-7) {
            v=(ll+rr)/2.0;
            Bfs();
            if (f[e.x][e.y]<l) ll=v+1e-7;
            else rr=v;
        }
        printf("%.5lf
",v);
    }
}
View Code

 

以上是关于[二分][记搜]JZOJ 3522 迷宫花园的主要内容,如果未能解决你的问题,请参考以下文章

[二分][排序] JZOJ P1792 教主的花园

二分+最短路判定 BZOJ 2709: [Violet 1]迷宫花园

jzoj6.24模拟B

[DP][二分]JZOJ 3463 军训

[DP][二分]JZOJ 3467 最长上升子序列

LeetCode 5187. 收集足够苹果的最小花园周长(式子化简,二分)