题意——

一个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 = ;
  9.  
  10. struct Node
  11. {
  12. int x, y;
  13. };
  14.  
  15. int dir[][] = {{, }, {, }, {-, }, {, -}};
  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 = ;
  26. vis[][] = ;
  27. if(mp[][] == '') q0.push(p);
  28. else
  29. {
  30. sxy[] = ;
  31. k = ;
  32. printf("");
  33. return ;
  34. }
  35. k = ;
  36. while(!q0.empty())
  37. {
  38. p = q0.front();
  39. q0.pop();
  40. sxy[k++] = p.x+p.y;
  41. if(p.x == n- && p.y == m-) return ;
  42. for(int i = ; i < ; i++)
  43. {
  44. int sx = p.x+dir[i][];
  45. int sy = p.y+dir[i][];
  46. if(sx >= && sx < n && sy >= && sy < m && !vis[sx][sy] && mp[sx][sy] == '')
  47. {
  48. vis[sx][sy] = ;
  49. ps.x = sx;
  50. ps.y = sy;
  51. q0.push(ps);
  52. }
  53. }
  54. }
  55. return ;
  56. }
  57.  
  58. void sroot()
  59. {
  60. rt = ;
  61. for(int i = ; i < k; i++) if(rt < sxy[i]) rt = sxy[i];
  62. }
  63.  
  64. void getans()
  65. {
  66. for(int i = rt+; i <= m+n-; i++)
  67. {
  68. k = ;
  69. if(i >= n-) k = i-n+;
  70. int tmp = ;
  71. for(int j = k; j < m && j <= i; j++)
  72. {
  73. if((i-j- >= && i-j < n && j >= && vis[i-j-][j])
  74. || (i-j >= && i-j < n && j- >= && vis[i-j][j-]))
  75. {
  76. int mid = mp[i-j][j]-'';
  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- >= && i-j < n && j >= && vis[i-j-][j])
  84. || (i-j >= && i-j < n && j- >= && vis[i-j][j-]))
  85. {
  86. if(mp[i-j][j]-'' == tmp) vis[i-j][j] = ;
  87. }
  88. }
  89. }
  90. printf("\n");
  91. }
  92.  
  93. void init()
  94. {
  95. scanf("%d%d", &n, &m);
  96. for(int i = ; i < n; i++) scanf("%s", mp[i]);
  97. memset(vis, , 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\n");
  110. else
  111. {
  112. sroot();
  113. getans();
  114. }
  115. }
  116. return ;
  117. }

hdu 5335 Walk Out(bfs+斜行递推) 2015 Multi-University Training Contest 4的更多相关文章

  1. HDU 5335 Walk Out BFS 比较坑

    H - H Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status ...

  2. hdu 5335 Walk Out(bfs+寻找路径)

    Problem Description In an n∗m maze, the right-bottom corner or a written on it. An explorer gets los ...

  3. HDU 5335 Walk Out (BFS,技巧)

    题意:有一个n*m的矩阵,每个格子中有一个数字,或为0,或为1.有个人要从(1,1)到达(n,m),要求所走过的格子中的数字按先后顺序串起来后,用二进制的判断大小方法,让这个数字最小.前缀0不需要输出 ...

  4. hdu 5335 Walk Out (搜索)

    题目链接: hdu 5335 Walk Out 题目描述: 有一个n*m由0 or 1组成的矩形,探险家要从(1,1)走到(n, m),可以向上下左右四个方向走,但是探险家就是不走寻常路,他想让他所走 ...

  5. HDU 5459 Jesus Is Here(递推)

    http://acm.hdu.edu.cn/showproblem.php?pid=5459 题意: S(1) = c,S(2) = ff, S(3) = cff,之后S(i) = S(i-1)+S( ...

  6. HDU 4834 JZP Set(数论+递推)(2014年百度之星程序设计大赛 - 初赛(第二轮))

    Problem Description 一个{1, ..., n}的子集S被称为JZP集,当且仅当对于任意S中的两个数x,y,若(x+y)/2为整数,那么(x+y)/2也属于S.例如,n=3,S={1 ...

  7. HDU 2050 折线分割平面 (递推)

    题意:略. 析:多写几个就找到规律了,第1条是2,2条时是7个,3条时是16,4条时是29,.... 那么规律就出来了2 * n * n + 1 - n; 也可以递推,第n条折线的两条边都与前n-1条 ...

  8. HDU - 6172:Array Challenge (BM线性递推)

    题意:给出,三个函数,h,b,a,然后T次询问,每次给出n,求sqrt(an); 思路:不会推,但是感觉a应该是线性的,这个时候我们就可以用BM线性递推,自己求出前几项,然后放到模板里,就可以求了. ...

  9. HDU - 2604 矩阵快速幂 字符串递推 两种解法

    记dp[i]为长度i且符合题意的方案数,dp[n]就是解 符合方案的是不含fmf和fff子串的字符串 考虑如何从前面几项递推出后面第i项 (★表示存在生成的非法方案)←其实没啥用处 i=1时 m③ f ...

随机推荐

  1. MSVC CRT运行库启动代码分析

    原文链接:http://www.programlife.net/msvc-crt-startup.html 在程序进入main/WinMain函数之前,需要先进行C运行库的初始化操作,通过在Visua ...

  2. SDUT2141数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历

    http://acm.sdut.edu.cn/sdutoj/showproblem.php?pid=2141&cid=1186 #include<cstdio> #include& ...

  3. Gulp实战和原理解析

    Gulp实战和原理解析(以weui作为项目实例)http://i5ting.github.io/stuq-gulp/

  4. HUSTOJ(转发)

    来源:http://blog.csdn.net/xiajian2010/article/details/12954855 缘起 大四了,快毕业了,所以想准备点LAMP的知识和经验.刚好实验室里有人在搞 ...

  5. FWT 学习总结

    我理解的FWT是在二元运算意义下的卷积 目前比较熟练掌握的集合对称差卷积 对于子集卷积和集合并卷积掌握不是很熟练(挖坑ing) 那么就先来谈一谈集合对称差卷积吧 所谓集合对称差卷积 就是h(i)=si ...

  6. Linux进程管理知识整理

    Linux进程管理知识整理 1.进程有哪些状态?什么是进程的可中断等待状态?进程退出后为什么要等待调度器删除其task_struct结构?进程的退出状态有哪些? TASK_RUNNING(可运行状态) ...

  7. spring中的aware接口

    1.实现了相应的aware接口,这个类就获取了相应的资源. 2.spring中有很多aware接口,包括applicationContextAware接口,和BeanNameAware接口. 实现了这 ...

  8. GuessNumber

    import java.util.*; public class GuessNumber { public static void main(String[] args) { int num = ne ...

  9. QT 焦点事件(4种方式的解释,还有委托焦点)

    1.setFocusPolicy(...)设置获得焦点的方式 Qt::TabFocus 通过Tab键获得焦点 Qt::ClickFocus 通过被单击获得焦点 Qt::StrongFocus 可通过上 ...

  10. 机器人学 —— 飞行机器人(Introduction)

    UPNN课程 aerial robotics 教授: VJ  Kummer 1.四旋翼飞行器的控制对象是各个旋翼对应的电机 2.飞行器的能源主要消耗于hovering. 3.飞行器在设计时需要考虑各个 ...