HDU 5335 Walk Out (BFS,技巧)

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

思路:主要考虑的是BFS解决。

  如果grid[1,1]=1,那么这个二进制的位数也就定下来了,是n+m-1,很好解决,每个格子就只能往下或者往右,否则长度一定超过n+m+1,必定不是最优。

  如果grid[1,1]=0,那么可能会出现绕了一个S型到终点的结果为0而已。所以不能用老办法,要先预处理一下。处理方式是,用BFS将所有grid[1,1]可达的0点标记出来,找出其中距离终点最近的那些0点(可能多个),如果他们的下和右边的点为1,这些点都进队,再用上边方式BFS即可求得答案(上面只是1个起点,这边有多个起点,不影响正确性)。

  答案在哪?其实在BFS时每一层只能是0点或者是1点,为什么呢?如果有0点的话,还需要选择1点的吗?别忘了二进制的位数是固定了,选0肯定比选1要好,则在没有0的情况下再选1的。 在遍历时按层遍历,遍历到的点先分到两个集合A0和B1中,择所需即可,所以在遍历第i层时第i位的答案也就决定了。这是剪枝!

  注意考虑只有1个点,2个点和S形等各种情况。

  1 #include <bits/stdc++.h>
  2 #define INF 0x7f7f7f7f
  3 #define pii pair<int,int>
  4 #define LL unsigned long long
  5 using namespace std;
  6 const int N=1005;
  7 int n, m;
  8 char grid[N][N];
  9 vector<int> ans;
 10 int inq[N][N];
 11
 12 void BFS(deque<pii> &que)
 13 {
 14     ans.push_back(1);
 15     while(!que.empty())
 16     {
 17         deque<pii> que0, que1;      //两种到达的方式,只取其一
 18         int siz=que.size();
 19         for(int i=0; i<siz; i++)    //被更新的都是同一源头的。
 20         {
 21             int a=que.front().first;
 22             int b=que.front().second;
 23             que.pop_front();
 24
 25             if( a+1<=n && !inq[a+1][b] )    //下:要么你无路径可达,要么我比你小,我才更新你
 26             {
 27                 if(grid[a+1][b]==‘0‘)    que0.push_back(make_pair(a+1,b));
 28                 else                     que1.push_back(make_pair(a+1,b));
 29             }
 30             if( b+1<=m && !inq[a][b+1] )    //右
 31             {
 32                 if(grid[a][b+1]==‘0‘)    que0.push_back(make_pair(a,b+1));
 33                 else                     que1.push_back(make_pair(a,b+1));
 34             }
 35             inq[a+1][b]=inq[a][b+1]=1;
 36         }
 37
 38         if(!que0.empty())    ans.push_back(0);
 39         else                 ans.push_back(1);
 40
 41         if(!que0.empty())    que.insert(que.end(), que0.begin(), que0.end() );
 42         else                 que.insert(que.end(), que1.begin(), que1.end() );
 43     }
 44 }
 45
 46
 47 int cal()
 48 {
 49     memset(inq, 0, sizeof(inq));
 50
 51     deque<pii> que;que.push_back( make_pair(1,1));
 52     if(grid[1][1]==‘0‘) //若起点为0,找到所有离终点最近的前缀0
 53     {
 54         inq[1][1]=1;
 55         while(!que.empty())
 56         {
 57             int siz=que.size();
 58             for(int i=0; i<siz; i++)    //按层来BFS,按层记录最优答案
 59             {
 60                 int a=que.front().first;
 61                 int b=que.front().second;
 62                 que.pop_front();
 63
 64                 if(a+1<=n && !inq[a+1][b] && grid[a+1][b]==‘0‘)    que.push_back(make_pair(a+1,b));
 65                 if(a-1>0  && !inq[a-1][b] && grid[a-1][b]==‘0‘)    que.push_back(make_pair(a-1,b));
 66
 67                 if(b+1<=m && !inq[a][b+1] && grid[a][b+1]==‘0‘)    que.push_back(make_pair(a,b+1));
 68                 if(b-1>0  && !inq[a][b-1] && grid[a][b-1]==‘0‘)    que.push_back(make_pair(a,b-1));
 69
 70                 inq[a+1][b]=inq[a-1][b]=inq[a][b+1]=inq[a][b-1]=1;  //防止重复进队
 71             }
 72         }
 73         int min_dis=INF;
 74         for(int i=1; i<=n; i++) //求最近的0距离终点的最小距离
 75         {
 76             for(int j=1; j<=m; j++)
 77             {
 78                 if(inq[i][j]&&grid[i][j]==‘0‘)
 79                     min_dis=min(min_dis, n+m-j-i);
 80             }
 81         }
 82         if(grid[n][m]==‘0‘ && min_dis==0) return 0;   //有0路可达终点
 83         for(int i=1; i<=n; i++)         //扫出距离为min_dis的所有0点
 84             for(int j=1; j<=m; j++)
 85                 if(inq[i][j] && grid[i][j]==‘0‘ && min_dis==n+m-j-i && n+m-i-j!=0 )
 86                     que.push_back(make_pair(i,j));
 87
 88         memset(inq,0,sizeof(inq));
 89         int siz=que.size();
 90         for(int i=0; i<siz; i++)    //将所有0点的下和右为1的点进队
 91         {
 92             int a=que.front().first;
 93             int b=que.front().second;
 94             que.pop_front();
 95             if(a+1<=n&&!inq[a+1][b]&&grid[a+1][b]==‘1‘)    que.push_back(make_pair(a+1,b));
 96             if(b+1<=m&&!inq[a][b+1]&&grid[a][b+1]==‘1‘)    que.push_back(make_pair(a,b+1));
 97             inq[a+1][b]=inq[a][b+1]=1;
 98         }
 99     }
100     BFS(que);
101     return ans.size();
102 }
103
104 int main()
105 {
106     freopen("input.txt", "r", stdin);
107     int t, a, b;
108     char c;
109     cin>>t;
110     while(t--)
111     {
112         ans.clear();
113         scanf("%d %d",&n,&m);
114
115         for(int i=1; i<=n; i++) //输入要注意
116             for(int j=1; j<=m; j++)
117             {
118                 c=getchar();
119                 if(c==‘0‘||c==‘1‘ ) grid[i][j]=c;
120                 else    j--;
121             }
122         int s=cal();
123         if(s==0)    printf("0");
124         else    for(int i=0; i+1<ans.size(); i++)    printf("%d",ans[i]);//最后一个数字多余
125         printf("\n");
126     }
127     return 0;
128 }

AC代码

时间: 2024-11-08 00:54:55

HDU 5335 Walk Out (BFS,技巧)的相关文章

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

Problem Description In an n∗m maze, the right-bottom corner is the exit (position (n,m) is the exit). In every position of this maze, there is either a 0 or a 1 written on it. An explorer gets lost in this grid. His position now is (1,1), and he want

hdu 5335 Walk Out (搜索)

题目链接: hdu 5335 Walk Out 题目描述: 有一个n*m由0 or 1组成的矩形,探险家要从(1,1)走到(n, m),可以向上下左右四个方向走,但是探险家就是不走寻常路,他想让他所走的路线上的0/1组成的二进数最小,现在要为矫情无比的探险家找最优路径咯. 解题思路: 对于二进制数,前导零是对数字大小没有任何影响的.当到不得不走1的时候就只能向下,或者向右走了.所以先搜索出来一直走零,能走到的最靠近终点的位置,然后在类似搜索,找出最优路径. 1 #include <queue>

HDU 5335 Walk Out(Bfs搜索字典序最小的最短路)

 题意:nXm的地图, 问通过四个方向从(1,1)走到(1000,1000)所经过的最小二进制序列是多少,忽略前缀0. 思路:首先如果起点为0,那么我们bfs搜索和起点0联通的为0的连通块,这样我们第一步肯定是从与这个连通块相邻的且与重点最近的地方出发. 将所有可能起点加入队列,在bfs一遍找到字典序最小的那条路就是答案, 在这里可以用两个vector类型容器,一个是q2存储所有节点值存为0的结点, 另一个q3存储节点值为1的结点. 那么如果q2不为空那么也就是有可以走零,那么就从这里面选,

HDU 5335 Walk Out (搜索+贪心,超详解)经典

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5335 题面: Walk Out Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2355    Accepted Submission(s): 459 Problem Description In an n?m maze, the righ

HDU 5335 Walk Out(多校)

Walk Out Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2912    Accepted Submission(s): 599 Problem Description In an n∗m maze, the right-bottom corner is the exit (position (n,m) is the exit).

HDU 5335——Walk Out——————【贪心】

Walk Out Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1292    Accepted Submission(s): 239 Problem Description In an n∗m maze, the right-bottom corner is the exit (position (n,m) is the exit).

HDU 5335 Walk Out

题意:在一个只有0和1的矩阵里,从左上角走到右下角, 每次可以向四个方向走,每个路径都是一个二进制数,求所有路径中最小的二进制数. 解法:先bfs求从起点能走到离终点最近的0,那么从这个点起只向下或向右走就可以获得位数最少的二进制数,然后贪心的想,如果后或下有0就一定走0,没0就把1都看一遍,以之前搜到的0做起点,一层一层遍历可行路径,直到终点. 代码: #include<stdio.h> #include<iostream> #include<algorithm> #

HDU 5335 多校第4场 1009 Walk Out

Walk Out Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1794    Accepted Submission(s): 340 Problem Description In an n?m maze, the right-bottom corner is the exit (position (n,m) is the exit)

HDU 5001 Walk(鞍山网络赛E题)

HDU 5001 Walk 题目链接 思路:枚举每个要经过的点,然后进行状态转移,状态为dp[i][j],状态表示当前在j的点,已经走了i步,每次转移的时候,不从这个枚举的点出发,这样就可以求出所有路径经过该点的概率p, 然后1 - p就是不经过的答案 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; con