刚开始按(wqy)的思路写,提交了(n)遍也没过。。。
学到了压成一维。
还是梳理梳理错因吧:
- 1.对每个井号进行(bfs),会超时(我真是太傻逼了)。
- 2.对于(0)的情况,一个点如果之前被标记过,并且之前被标记的和现在要标记的值不一样,答案才会是(0)。
- 3.在初始化的时候也要判断2中的情况(之前被标记过),因为有一行(或者一列)的情况。
- 4.(wqy)说的四周是周围(8)个格子。
- 5.对于一个点,如果进队了要标记,防止进队很多次。((test\,10)
- 6.关于出队清不清标记???((test\,18)
改成出队不清标记,进队是没有标记才进。才同时过了10,18
先贴一份没有(AC)的代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 2e6+5;
int n,m,a[N],id[N],qx[N],qy[N],l=1,r;
int dx[10]={0,0,1,-1,0,-1,1,-1,1};
int dy[10]={0,1,0,0,-1,-1,1,1,-1};
bool book[N],flag=0;
char c;
/*int bft(int x,int y)
{
memset(book,0,sizeof(book));
qx[1]=x; qy[1]=y;
l=r=1;
bool flag1=0,flag2=0;
if(x==n||y==1) flag1=1;
if(x==1||y==m) flag2=1;
while(l<=r)
{
if(flag1&&flag2) break;
// if(flag3&&t) return 5;
int xt=qx[l],yt=qy[l],xx,yy;
++l;
for(int i=1;i<=8;i++)
{
// if(t&&i==3) break;
xx=xt+dx[i],yy=yt+dy[i];
if(xx>n||yy>m) continue;
if(xx<1||yy<1) continue;
if(a[(xx-1)*m+yy]==0&&!book[(xx-1)*m+yy])
{
qx[++r]=xx; qy[r]=yy;
book[(xx-1)*m+yy]=1;
if(xx==n||yy==1) flag1=1;
if(xx==1||yy==m) flag2=1;
// if(xx==n&&yy==m) flag3=1;
}
}
}
// if(flag3&&t) return 5;
if(flag1&&flag2) return 3;
if(flag1) return 1;
if(flag2) return 2;
return 0;
}*/
void bfs()
{
while(l<=r)
{
int xt=qx[l],yt=qy[l],xx,yy;
++l;
// book[(xt-1)*m+yt]=0;
for(int i=1;i<=8;i++)
{
xx=xt+dx[i],yy=yt+dy[i];
if(xx<1||xx>n) continue;
if(yy<1||yy>m) continue;
if(!a[(xx-1)*m+yy])
{
if(id[(xx-1)*m+yy]!=0&&id[(xx-1)*m+yy]!=id[(xt-1)*m+yt])
{ flag=1; return ; }
// { flag=1; return ;}
id[(xx-1)*m+yy]=id[(xt-1)*m+yt];
// printf("%d %d %d
",r,xx,yy);
if(!book[(xx-1)*m+yy]) qx[++r]=xx,qy[r]=yy;
book[(xx-1)*m+yy]=1;
}
}
}
// cout<<flag<<"*******"<<endl;
// cout << r <<endl;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>c;
if(c=='.') a[(i-1)*m+j]=1;
else a[(i-1)*m+j]=0;
}
// 1 左下 2 右上
for(int i=1;i<=n;i++)
{
if(a[(i-1)*m+1]==0&&id[(i-1)*m+1]==2) { printf("0
"); return 0; }
if(a[(i-1)*m+1]==0) { id[(i-1)*m+1]=1,qx[++r]=i,qy[r]=1,book[(i-1)*m+1]=1;}
if(a[(i-1)*m+m]==0&&id[i*m]==1) { printf("0
"); return 0; }
if(a[(i-1)*m+m]==0) { id[i*m]=2,qx[++r]=i,qy[r]=m,book[i*m]=1;}
}
for(int i=1;i<=m;i++)
{
if(a[i]==0&&id[i]==1) { printf("0
"); return 0; }
if(a[i]==0) { id[i]=2,qx[++r]=1,qy[r]=i,book[i]=1;}
if(a[(n-1)*m+i]==0&&id[(n-1)*m+i]==2) { printf("0
"); return 0; }
if(a[(n-1)*m+i]==0) { id[(n-1)*m+i]=1,qx[++r]=n,qy[r]=i,book[(n-1)*m+i]=1; }
}
/* for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cout<<id[(i-1)*m+j]<<"*";
cout<<endl;
}*/
bfs();
if(flag) { printf("0
"); return 0; }
bool a1=0,a2=0;
/* for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[(i-1)*m+j]==0&&!id[(i-1)*m+j])
{
a1=0,a2=0;
for(int k=1;k<=8;k++)
{
if(i+dx[k]<=0||i+dx[k]>n) continue;
if(j+dy[k]<=0||j+dy[k]>m) continue;
if(id[(i+dx[k]-1)*m+j+dy[k]]==1) a1=1;
if(id[(i+dx[k]-1)*m+j+dy[k]]==2) a2=1;
}
if(a1==1&&a2==1) { printf("0
"); return 0;}
if(a1==1) id[(i-1)*m+j]=1;
if(a2==1) id[(i-1)*m+j]=2;
}*/
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
// if(a[(i-1)*m+j]==1)
{
if(i==1&&j==1) continue;
if(i==n&&j==m) continue;
a1=0,a2=0;
if(i==n||j==1) a1=1;
if(i==1||j==m) a2=1;
for(int k=1;k<=8;k++)
{
if(i+dx[k]<=0||i+dx[k]>n) continue;
if(j+dy[k]<=0||j+dy[k]>m) continue;
if(id[(i+dx[k]-1)*m+j+dy[k]]==1) a1=1;
if(id[(i+dx[k]-1)*m+j+dy[k]]==2) a2=1;
}
if(a1&&a2)
{
if(a[(i-1)*m+j]==0) { printf("0
"); return 0; }
else { printf("1
"); return 0; }
}
}
printf("2
");
return 0;
}
(Dyj)太神辣!!!
思路:
先判断0的情况。
对于剩下两种情况:
1.找一条最靠右,或最靠下的路径,把它全部标记上,再在标记后的新矩阵中找是否有从(1,1)到(n,m)的路径,如果有,答案为2,如果没有,答案为1.
2.如果答案为1,那么所有可行的路径必然经过同一个点(该标记的点,记为(w)),对于可行路径中,交点最少的两条路径一定是最靠右的一条和最靠下的一条。如果这两条路径有交点,那么答案为1,否则为2。
对1的感性证明:
如果答案为1的话,标记一条路径,那么(w)一定会被标记。但是标记任意一条不行,这样会把应该是2的答案判成1。
为什么呢?
因为标记一整条路径的话,除了(w)点是应该标记的,还会多标记好多点。假如其中某一个点是某一条可以不经过(w)点到(n,m)的路径必须经过的点的话,就会出错。
还是画个样例吧:
如果标记了红色的路径,就会错判为答案是1。
但是标记最右,或最下的路径,就不会出现这种情况。(感性理解吧 )
不得不再说一遍,(Dyj)太强了。
按刁神的思路,我一直写(T)。
(dfs)时先向右走,再向下走。既然这样(T)的话,能不能每次只向一个方向走,反正找到一条路径就可以了嘛。
但是,这样不行。
原因:如果一个点能向右走,但是向右走几个格之后就没路了,所以在这个格应该向下走,但是已经向右走过了,所以向下的搜不到了。
刁神的神奇做法:
第一遍判情况0时的(bfs)对每个点记录一个相当于(dis)的值,每个点的(dis)都等于从它转移过来的那个点的(dis+1)。然后(dfs)找路径标记的时候,从(n,m)向左上走,假如接下来要搜的点的(dis)等于当前点的(dis-1),那么才搜,否则不搜。
推荐大佬的博客
一样没有(AC)的代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 1e6+10;
int n,m,a[N],qx[N],qy[N],l=1,r;
bool book[N],flag;
char c;
void work()
{
/* for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cout<<book[(i-1)*m+j]<<"*";
cout<<endl;
}*/
book[n*m]=0;
flag=1;
bool at=0;
qx[++r]=1, qy[r]=1;
while(l<=r)
{
int xt=qx[l],yt=qy[l]; ++l;
if(xt==n&&yt==m) { at=1; printf("2
"); return ; }
if(xt+1<=n&&!book[xt*m+yt]&&a[xt*m+yt])
qx[++r]=xt+1,qy[r]=yt,book[xt*m+yt]=1;
if(yt+1<=m&&!book[(xt-1)*m+yt+1]&&a[(xt-1)*m+yt+1])
qx[++r]=xt,qy[r]=yt+1,book[(xt-1)*m+yt+1]=1;
}
if(!at) printf("1
");
return ;
}
void dfs(int x,int y)
{
if(x==n&&y==m) { work(); return ;}
if(flag) return ;
if(x>n||x<1) return ;
if(y<1||y>m) return ;
if(a[(x-1)*m+y+1]==1&&y+1<=m)
{ book[(x-1)*m+y+1]=1; dfs(x,y+1); book[(x-1)*m+y+1]=0;}
if(a[x*m+y]==1&&x+1<=n)
{ book[x*m+y]=1; dfs(x+1,y); book[x*m+y]=0;}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>c;
if(c=='.') a[(i-1)*m+j]=1;
}
book[1]=1;
dfs(1,1);
if(flag==0) printf("0
");
return 0;
}