• hdu 5335 Walk Out(bfs+斜行递推) 2015 Multi-University Training Contest 4


    题意——

    一个n*m的地图,从左上角走到右下角。

    这个地图是一个01串,要求我们行走的路径形成的01串最小。

    注意,串中最左端的0全部可以忽略,除非是一个0串,此时输出0。

    例:

    3 3

    001

    110

    001

    此图的最短路径为101。

    输入——

    第一行输入一个整数t,表示共有t组数据。

    接下来每组第一行输入两个整数n, m。表示地图的长和宽。

    接下来n行,每行m个字符。字符只有0或1。

    输出——

    输出一个字符串,表示最短路径。

    这道题刚开始用了优先队列+大数写的bfs,然后无限爆tle,后来想了想——

    首先,用优先队列时,每个节点入队的时间复杂度为log2(k),其中k为当前队列的长度。

    其次,大数每次乘2的操作都要len次,每次在入队时和其他节点比较时还可能要len次,len为数的长度。

    而地图最大是1000*1000的,总共的时间复杂度粗略算一下要10^6*log2(10^3)*40,刚好卡在时限上了,再乘上一个常数,就超时了,再乘上t,更超时了。

    不能用优先队列,用普通队列,怎么写想了好久,在比赛结束之后又看了一下题解,发现大概有一下几种解法——

    1. 先搜出来从起点出发的所有0,此时起点必须是0,用bfs向4个方向搜;然后从所有0出发,寻找到终点的点,用bfs向下或向右走;然后再从终点出发,往回走,用dfs;然后就看不懂了……
    2. 先搜出来从起点出发的所有0,此时起点必须是0,用bfs向4个方向搜;然后在这些0中选取行号和列号相加最大的点,因为这些点距离终点最近,可以得知,这些点在同一斜行,然后从这些点所在的斜行的下一斜行开始,一行一行向下进行递推——优先选取0,对本斜行中选取的字符标记,然后对下一斜行进行递推时,只考虑可以从标记点走到的点。

    当然,当对0进行搜索时,已经搜到终点,那么输出0就可以了。

    我用的是第二种方法。

    耗时109ms,内存4520k。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cmath>
      4 #include <algorithm>
      5 #include <queue>
      6 using namespace std;
      7 
      8 const int N = 1010;
      9 
     10 struct Node
     11 {
     12     int x, y;
     13 };
     14 
     15 int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
     16 int sxy[N*N];
     17 char mp[N][N];
     18 bool vis[N][N];
     19 int n, m, t, rt, k;
     20 queue<Node> q0;
     21 
     22 int bfs0()
     23 {
     24     Node p, ps;
     25     p.x = p.y = 0;
     26     vis[0][0] = 1;
     27     if(mp[0][0] == '0') q0.push(p);
     28     else
     29     {
     30         sxy[0] = 0;
     31         k = 1;
     32         printf("1");
     33         return 0;
     34     }
     35     k = 0;
     36     while(!q0.empty())
     37     {
     38         p = q0.front();
     39         q0.pop();
     40         sxy[k++] = p.x+p.y;
     41         if(p.x == n-1 && p.y == m-1) return 1;
     42         for(int i = 0; i < 4; i++)
     43         {
     44             int sx = p.x+dir[i][0];
     45             int sy = p.y+dir[i][1];
     46             if(sx >= 0 && sx < n && sy >= 0 && sy < m && !vis[sx][sy] && mp[sx][sy] == '0')
     47             {
     48                 vis[sx][sy] = 1;
     49                 ps.x = sx;
     50                 ps.y = sy;
     51                 q0.push(ps);
     52             }
     53         }
     54     }
     55     return 0;
     56 }
     57 
     58 void sroot()
     59 {
     60     rt = 0;
     61     for(int i = 0; i < k; i++) if(rt < sxy[i]) rt = sxy[i];
     62 }
     63 
     64 void getans()
     65 {
     66     for(int i = rt+1; i <= m+n-2; i++)
     67     {
     68         k = 0;
     69         if(i >= n-1) k = i-n+1;
     70         int tmp = 2;
     71         for(int j = k; j < m && j <= i; j++)
     72         {
     73             if((i-j-1 >= 0 && i-j < n && j >= 0 && vis[i-j-1][j])
     74                || (i-j >= 0 && i-j < n && j-1 >= 0 && vis[i-j][j-1]))
     75             {
     76                 int mid = mp[i-j][j]-'0';
     77                 tmp = tmp < mid ? tmp : mid;
     78             }
     79         }
     80         printf("%d", tmp);
     81         for(int j = k; j < m && j <= i; j++)
     82         {
     83             if((i-j-1 >= 0 && i-j < n && j >= 0 && vis[i-j-1][j])
     84                || (i-j >= 0 && i-j < n && j-1 >= 0 && vis[i-j][j-1]))
     85             {
     86                 if(mp[i-j][j]-'0' == tmp) vis[i-j][j] = 1;
     87             }
     88         }
     89     }
     90     printf("
    ");
     91 }
     92 
     93 void init()
     94 {
     95     scanf("%d%d", &n, &m);
     96     for(int i = 0; i < n; i++) scanf("%s", mp[i]);
     97     memset(vis, 0, sizeof(vis));
     98     while(!q0.empty()) q0.pop();
     99 }
    100 
    101 int main()
    102 {
    103     //freopen("test.in", "r", stdin);
    104     //freopen("test.out", "w", stdout);
    105     scanf("%d", &t);
    106     while(t--)
    107     {
    108         init();
    109         if(bfs0()) printf("0
    ");
    110         else
    111         {
    112             sroot();
    113             getans();
    114         }
    115     }
    116     return 0;
    117 }
    View Code
  • 相关阅读:
    SpringBoot处理跨域的四种方式
    centos部署nextcloud
    nginx反向代理时配置访问密码
    java对redis的基本操作
    springboot使用redis
    Linux安装redis
    centos安装php7.2环境 (亲测可用)
    linux下后台启动springboot项目
    全局加token
    web移动端浮层滚动阻止window窗体滚动JS/CSS处理
  • 原文地址:https://www.cnblogs.com/mypride/p/4693712.html
Copyright © 2020-2023  润新知