zoukankan      html  css  js  c++  java
  • nyoj306 二分+DFS

    走迷宫

    时间限制:1000 ms  |  内存限制:65535 KB
    难度:5
     
    描述
    Dr.Kong设计的机器人卡多非常爱玩,它常常偷偷跑出实验室,在某个游乐场玩之不疲。这天卡多又跑出来了,在SJTL游乐场玩个不停,坐完碰碰车,又玩滑滑梯,这时卡多又走入一个迷宫。整个迷宫是用一个N * N的方阵给出,方阵中单元格中填充了一个整数,表示走到这个位置的难度。

    这个迷宫可以向上走,向下走,向右走,向左走,但是不能穿越对角线。走迷宫的取胜规则很有意思,看谁能更快地找到一条路径,其路径上单元格最大难度值与最小难度值之差是最小的。当然了,或许这样的路径不是最短路径。

         机器人卡多现在在迷宫的左上角(第一行,第一列)而出口在迷宫的右下角(第N行,第N列)。

    卡多很聪明,很快就找到了这样的一条路径。你能找到吗?

     
    输入
    有多组测试数据,以EOF为输入结束的标志
    第一行: N 表示迷宫是N*N方阵 (2≤ N≤ 100)
    接下来有N行, 每一行包含N个整数,用来表示每个单元格中难度 (0≤任意难度≤120)。
    输出
    输出为一个整数,表示路径上最高难度与和最低难度的差。
    样例输入
    5
    1 1 3 6 8
    1 2 2 5 5
    4 4 0 3 3
    8 0 2 3 4
    4 3 0 2 1
    样例输出
    2
    来源
    第四届河南省程序设计大赛
    上传者
    张云聪
    上下左右四个方向,走的方式太多了简直无法暴力搜索。难度差最大为120,考虑从这里下手,
    找出迷宫中的最大值与最小值,这两个数的差值就是最大的难度差,最小的难度差为零,然后二分在这个区间里枚举难度差直到找到最优解。
    切记不要多此一举的回溯,这样会导致TLE(并不是每个搜索都需要回溯)。
    找到mid=(l+r)/2,然后把难度差控制在[l,mid]直接搜索,若有解则将r的值更新为mid,否则将l的值更新为mid+1,每次都会缩小一半的范围;
    对于给定的一个mid,找到所有符合条件的区间逐个枚举,发现路径后及时退出。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int n,ok,e[105][105];
    int minn=999999999,maxn=-1;
    bool vis[105][105];
    int fx[4][2]={-1,0,1,0,0,1,0,-1};
    int read()
    {
    int s=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') {s=s*10+ch-'0';ch=getchar();}
    return s;
    }
    void dfs(int x,int y,int l,int r)
    {
    if(ok) return;
    if(x==n&&y==n) {ok=1;return;}
    for(int i=0;i<4;++i){if(ok) return;
    int dx=x+fx[i][0];
    int dy=y+fx[i][1];
    if(dx>=1&&dy>=1&&dx<=n&&dy<=n&&e[dx][dy]>=l&&e[dx][dy]<=r&&!vis[dx][dy]){
    vis[dx][dy]=1;
    dfs(dx,dy,l,r);
    //vis[dx][dy]=0;
    }
    }
    }
    bool Find(int k)
    {
    for(int i=minn;i+k<=maxn;++i){

    if(e[1][1]<i||e[1][1]>i+k) continue;//当前地图值不在查找范围内
    if(e[n][n]<i||e[n][n]>i+k) continue;
    ok=0;
    memset(vis,0,sizeof(vis));
    vis[1][1]=1;
    dfs(1,1,i,i+k);
    if(ok) return true;
    }
    return false;
    }
    int solve()
    {
    int l=0,r=maxn-minn,mid;
    while(l<r){
    mid=(l+r)/2; //cout<<mid<<endl;
    if(Find(mid)) r=mid;
    else l=mid+1;
    }
    return l;
    }
    int main()
    {
    int i,j;
    while(cin>>n){minn=999999999;maxn=-1;
    for(i=1;i<=n;++i)
    for(j=1;j<=n;++j) {e[i][j]=read();
    if(e[i][j]<minn) minn=e[i][j];
    if(e[i][j]>maxn) maxn=e[i][j];
    }//cout<<minn<<" "<<maxn<<endl;
    printf("%d ",solve());
    }
    return 0;
    }

  • 相关阅读:
    多字段截取然后验证 js
    web端上传图片,截取证件照
    bootstrap学习
    响应式网站设计心得
    不懂这几个问题就落后了:Python、Android开发者必读!
    这48个Java技术点,让你的面试成功率提升5倍!
    C++之父谈C++:一天之内你就能学会出色使用C++
    常用正则表达式
    解决vs验证控件报错” WebForms UnobtrusiveValidationMode 需要“jquery”ScriptResourceMapping。请添加一个名为 jquery (区分大小写)的 ScriptResourceMapping”问题
    怎么就那么难啊我去
  • 原文地址:https://www.cnblogs.com/zzqc/p/6767921.html
Copyright © 2011-2022 走看看