首先很容易想到位数越少越小,所以说肯定选择向下或者向右的走向到终点(即最短路径为忧)
其次如果一开始(1,1)为0的话,如果有一段连续的0路径,可以选择先绕到离终点最近的0,这样前面全是前导0,对答案没有影响
所以说策略是先找到一段连续的0距终点最近,然后再在每层寻找最小的数字(这里说的层和距离都是斜过来的)
千万不能用dfs找每层的0....数据卡了这个,直接每次递推寻找最小值然后标记就好了(哭死了,当时因为这个超时没过)
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; #define N 1005 int n,m; int tx[4]={0,0,1,-1},ty[4]={1,-1,0,0}; char graph[N][N]; bool used[N][N]; int xx[1100000], yy[1100000]; void Bfsimilar(){ int i,j,k; memset(used,false,sizeof(used)); used[1][1] = true; int q=1,h=1; xx[q]=yy[q]=1; for (; q<=h ; q++) //递归形dfs拿时间换空间 if(graph[xx[q]][yy[q]]=='0'){ for(i=0;i<4;i++){ int X=xx[q]+tx[i], Y=yy[q]+ty[i]; if(X>0 && X<=n && Y>0 && Y<=m && !used[X][Y]){ //找到最近的1 h++; xx[h]=X; yy[h]=Y; used[X][Y]=true; } } } if(used[n][m] && graph[n][m]=='0') { //处理一直是0的情况 printf("0\n"); return; } int ma=0; for(i=1;i<=n;i++) for(j=1;j<=m;j++) if(used[i][j]) ma=max(ma,i+j); //找到最近的0 printf("1"); //printf("%d\n",ma); for(i=ma;i<n+m;i++){ char mi='1'; int temp1=max(1,i-m); int temp2=min(n,i-1); for(j=temp1;j<=temp2;j++) if(used[j][i-j]){ mi=min(mi, graph[j+1][i-j]); mi=min(mi, graph[j][i-j+1]); } printf("%c",mi); for(j=temp1;j<=temp2;j++) if(used[j][i-j]){ if(graph[j+1][i-j]==mi) used[j+1][i-j] =true; if(graph[j][i-j+1]==mi) used[j][i-j+1] =true; } } printf("\n"); } int main() { //freopen("in.txt", "r", stdin); int T; int i,j,k; scanf("%d",&T); while(T--){ scanf("%d %d",&n,&m); for(i=1;i<=n;i++) scanf("%s",graph[i]+1); for(i=0;i<=n+1;i++) graph[i][0]='2',graph[i][m+1]='2'; //将边界处理为2,方便之后的处理 for(i=0;i<= m+1;i++) graph[0][i]='2',graph[n+1][i]='2'; Bfsimilar(); } return 0; }