版权声明:装作自己有版权 https://blog.csdn.net/weixin_44574444/article/details/86682596
mzoj1355迷宫(本校oj)
mzoj(传送门)
题目描述
此题先需要分析一下这个数据范围,我开始没有分析数据范围(25的阶乘),用的深搜,结果还对了一组数据(10分哦)。只有说明数据太水,偷偷过了一组 。
附上dfs代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=50+5;
int n,ans=0,sum=0x3f3f3f;
int beginx=0,beginy=0,endx=0,endy=0;
int a[maxn][maxn],s[maxn],vis[maxn][maxn];
int dx[4]={0, 0,1,-1};
int dy[4]={1,-1,0, 0};
int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
void init()
{
freopen("input.txt","r",stdin);
}
void readdata()
{
memset(vis,false,sizeof(vis));
memset(a,0,sizeof(a));
n=read();
register char ch;
for(int i=1;i<=n;i++)
{
// printf("\n");
for(int j=1;j<=n;j++)
{
cin>>ch;
if (ch=='S'){
beginx=i,beginy=j;
a[beginx][beginy]=2;
}
if (ch=='E'){
endx=i;endy=j;
a[endx][endy]=2;
}
if (ch=='.') a[i][j]=true;
else if (ch=='X') a[i][j]=false;
// printf("%d ",a[i][j]);
}
}
// printf("\n%d %d %d %d",beginx,beginy,endx,endy);
}
void dfs(int x,int y,int step)
{
if(x<1 || y<1 || x>n || y>n) return;//超边界就返回
if(a[x][y]==0) return;//没得路就返回
if(vis[x][y]==1) return;//走过了就返回
vis[x][y]=1;//打上标记
if(x==endx && y==endy)//到终点了就进行判断
{
if(sum<step) return;//走的步数比得到的多就返回
if(sum>step)
{
ans=0;
sum=step;//如果得到了跟小的答案就将ans赋值为零,并更新sum
}
if(sum==step) ans++;//第一次为1,此后没有一中最短路把ans++
return;
}
for(int i=0;i<=3;i++)
{
int nx=x+dx[i];
int ny=y+dy[i];
if(a[nx][ny]==0) continue;
if(vis[nx][ny]==1) continue;
dfs(nx,ny,step+1);
vis[nx][ny]=0;
}
}
void work()
{
dfs(beginx,beginy,0);
printf("%d",sum);
printf("\n");
printf("%d",ans);
}
int main()
{
// init();
readdata();
work();
return 0;
}
就不做多余解释了,核心注释已打上。
此题的正解:动态规划!!!!!
用一个三元组f[t][i][j]来维护,其中t为走的步数,且走的最大步数就是把这个图形每个点走完,也就是n*n。i为当前的行数,j为当前的列数。以四个方向枚举int nx=i+dx[k];
int ny=j+dy[k];且我们需要判断一下是否超界我们只需要枚举他上一步的值也就是每次累加上它上一步的值f[t][i][j]+=f[t-1][nx][ny];
ok,附上代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=50+5;
const int maxm=800;
char a[maxn][maxn];
int f[maxm][maxn][maxn];
int n,sx,sy,ex,ey;
int dx[]={0,0, 0,1,-1};
int dy[]={0,1,-1,0, 0};
int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
void init()
{
freopen("input.txt","r",stdin);
}
void readdata()
{
n=read();
for(int i=0;i<n;i++)
scanf("%s",a[i]);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(a[i][j]=='S'){//先找到起点,以sx,sy维护出它的起点的横纵坐标
sx=i;
sy=j;
}
if(a[i][j]=='E'){//找终点坐标
ex=i;
ey=j;
}
}
}
void work()
{
memset(f,0,sizeof(f));
f[0][sx][sy]=1;//先付初值
for(int t=1;t<=n*n;t++)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(a[i][j]!='X')
for(int k=1;k<=4;k++)
{
int nx=i+dx[k];
int ny=j+dy[k];
if(nx>=0 && ny>=0 && nx<n && ny<n && a[i][j]!='X')
f[t][i][j]+=f[t-1][nx][ny];//每次累加上他上一步的值
}
}
for(int t=1;t<=n*n;t++)
if(f[t][ex][ey])//判断是否有值
{
printf("%d\n%d",t,f[t][ex][ey]);
break;
}
}
int main()
{
init();
readdata();
work();
return 0;
}