标签:
题意:大致意思是给一个n*m的01矩阵,起点为左上方(1,1),终点为右下方(n,m),求从左上方到右下方字典序自小的路径,如果路径都为0,则输出0。
分析:首先字典序最小,先要满足路径最短,再满足路径的值最小,路径最短的毫无疑问是越靠下或者越靠右,而且如果路径的前面为0,则可以认为是以第一个非0的点的为起点。因此这题可以转化为:先找出以起点为中心的连续为零的集合,再在其中找出x+y最大的一些点为起点,(当然如果s[1][1]==1,起点就是左上方),然后以这些点不断往下往右寻找下一排的最小值,然后以下一排的最小值的为起点的所有点再往下递推,直到终点。(这里每一排的递推的起点和终点推理可以画图推出),也就是用dfs搜四个方向,递推两个方向向下和向右。
图中的点值为x+y,当tot=2时,下一排的x的起点为tot-m>=tot-m?1为1,终点为i-n<=1?i-1:n,为1,后面的斜排同理
2 | 3 | 4 |
3 | 4 | 5 |
4 | 5 | 6 |
注意:之前博客提到的,由于这里用到dfs,而且栈最大要开4000000,(但是用bfs写就不需要了)所以在hdu交的话要手动扩栈,而且要用c++交。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include<vector> #pragma comment(linker,"/STACK:1024000000,1024000000") //手动扩栈 using namespace std; const int maxn = 1e3+5; int n,m; int tot; char s[maxn][maxn]; bool vis[maxn][maxn]; void dfs(int x,int y) { if(vis[x][y]||s[x][y]-'0') return;//边界条件 vis[x][y]=1; //能走到的点标记 if(x+y>tot) tot=x+y; //标记最靠下的斜线的x+y if(x<n) dfs(x+1,y); //向下 if(x>1) dfs(x-1,y); //向上 if(y<m) dfs(x,y+1); //向右 if(y>1) dfs(x,y-1); //向左 } void solve() { if(s[1][1]=='1'){ printf("1"); vis[1][1]=1; } else if(s[1][1]=='0'&&tot==m+n){ printf("0"); } for(int i=tot;i<n+m;i++){ int nw = 1; for(int j=(i-m>=1?i-m:1);j<=(i-n<=1?i-1:n);j++){//斜线的初始点到终点 int nx = j; int ny = i-j; if(vis[nx][ny]){//由上一排得到能走的点 if(nx<n) nw = min(s[nx+1][ny]-'0',nw);//右边 if(ny<m) nw = min(s[nx][ny+1]-'0',nw);//下边 } } for(int j=(i-m>=1?i-m:1);j<=(i-n<=1?i-1:n);j++){ int nx = j; int ny = i-j; if(vis[nx][ny]){ if(nx < n && s[nx+1][ny]-'0'==nw) vis[nx+1][ny]=1;//标记下一排能走的点 if(ny < m && s[nx][ny+1]-'0'==nw) vis[nx][ny+1]=1; } } printf("%d",nw); } printf("\n"); } int main() { int t; scanf("%d",&t); while(t--){ memset(vis,0,sizeof(vis)); tot=2; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%s",s[i]+1); dfs(1,1); solve(); } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/sin_xf/article/details/47253047