赞
踩
内存限制: 256 Mb时间限制: 1000 ms
题目描述
给定 n × m n×m n×m 个方格构成的图,每个格子都有一种地形:
有一些格子是墙,以符号 # 表示,墙不可通行。
有一些格子是空地,以符号 . 表示,空地可以通行。
请统计从左上角的方格出发,有多少种不同的路线可以以最短距离走到右下角。在行走过程中,不能进入地形为墙的方格,保证起点与终点方格地形不是墙。且行走时,只能移动到水平或垂直方向相邻的方格。
由于方案数可能很大,输出模 1 , 000 , 000 , 007 1,000,000,007 1,000,000,007 的余数。
输入格式
第一行:单个整数 n n n 与 m m m
第二行到第 n + 1 n+1 n+1 行:第 i + 1 i+1 i+1 行每行有 m m m 个整数表示第 i i i 行的地形。
输出格式
单个整数:表示路线方案模 1 , 000 , 000 , 007 1,000,000,007 1,000,000,007 的余数。
数据范围
30% 的数据, 1 ≤ n , m ≤ 4 1≤n,m≤4 1≤n,m≤4
60% 的数据, 1 ≤ n , m ≤ 10 1≤n,m≤10 1≤n,m≤10
100% 的数据, 1 ≤ n , m ≤ 1000 1≤n,m≤1000 1≤n,m≤1000
样例数据
输入:
3 3
…
.#.
…
输出:
2
题目给定了
n
×
m
n×m
n×m 的图形,‘#’是障碍,‘.’是通路。
而与普通的最优路径问题不同的是此题问的是最优路径的条数。
深搜中的剪枝与最优化剪枝不同,当步数相等时最优化剪枝会剪掉,因为要寻找的是路径长度,但是现在找的是路径条数,所以不能剪。
另外,结构体中的
p
o
s
pos
pos 表示步数,
x
x
x 与
y
y
y 表示坐标。
#include <bits/stdc++.h>
#define int long long
#define inf 1000000007
using namespace std;
int n,m,dp[1010][1010],dx[4]={0,1,0,-1},dy[4]={1,0,-1,0},num,cnt;
char a[1010][1010];
struct nod{
int x,y,pos;
}q[1000010];
int bfs(){
int head=1,tail=2;
q[1].x=1,q[1].y=1,q[1].pos=0;
while(head<tail){
if(q[head].x==n&&q[head].y==m)return q[head].pos;
int x=q[head].x,y=q[head].y;
for(int i=0;i<4;++i){
int xx=x+dx[i],yy=y+dy[i];
if(xx>0&&xx<=n&&yy>0&&yy<=m&&dp[xx][yy]==-1&&a[xx][yy]=='.'){
q[tail].x=xx,q[tail].y=yy,q[tail].pos=q[head].pos+1;
dp[xx][yy]=1;
++tail;
}
}
++head;
}
}
void f(int x,int y,int s){
if(s>=num){
if(x==n&&y==m&&s==num)cnt=(cnt+1)%inf;
return;
}
dp[x][y]=s;
for(int i=0;i<4;++i){
int xx=x+dx[i],yy=y+dy[i];
if((xx>0&&xx<=n&&yy>0&&yy<=m)&&(dp[xx][yy]==-1||dp[xx][yy]>=s+1)&&a[xx][yy]=='.')
f(xx,yy,s+1);
}
}
signed main(){
memset(dp,-1,sizeof(dp));
cin>>n>>m;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
cin>>a[i][j];
num=bfs();
memset(dp,-1,sizeof(dp));
f(1,1,0);
cout<<cnt<<endl;
return 0;
}
此时TLE三个点。
如果简单粗暴开个10,000,000数组肯定因数组不够越界而RE,所以在用了STL栈之后变为TLE。
其本质仍然是枚举每一条路径并计数,题目却要求模一个高达10亿的数,由此可见最坏计数次数必定大于10亿,超时不可避免。注意剪枝与上文同。
而现在的宽搜程序正是答案的基础。
#include <bits/stdc++.h>
#define int long long
#define inf 1000000007
using namespace std;
int n,m,dp[1010][1010],dx[4]={0,1,0,-1},dy[4]={1,0,-1,0},num=LONG_LONG_MAX,ans;
char a[1010][1010];
struct nod{
int x,y,pos;
};
queue<nod>q;
void bfs(){
q.push({1,1,0});
while(!q.empty()){
if(q.front().x==n&&q.front().y==m&&q.front().pos<=num){
num=q.front().pos;
ans=(ans+1)%inf;
}
int x=q.front().x,y=q.front().y;
if(q.front().pos<num)
for(int i=0;i<4;++i){
int xx=x+dx[i],yy=y+dy[i];
if(xx>0&&xx<=n&&yy>0&&yy<=m&&(dp[xx][yy]==-1||dp[xx][yy]==q.front().pos+1)&&a[xx][yy]=='.'){
q.push({xx,yy,q.front().pos+1});
dp[xx][yy]=q.back().pos;
}
}
q.pop();
}
}
signed main(){
memset(dp,-1,sizeof(dp));
cin>>n>>m;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
cin>>a[i][j];
bfs();
cout<<ans<<endl;
return 0;
}
注意:Dev-c++ 5.5.2 可能会报警(入队写法),但是网站交是可以过的。不放心的同学可以手写自构函数。
首先需要明白的是,因为宽搜的基本思想,所以步数消耗较大的状态一定在消耗少的后面,所以当枚举到第二个状态重复的点时前一个肯定还未出队,所以就可以把它们合并为一个状态。
定义结构体时新增
s
t
e
p
step
step 变量用于存储当前状态的方案数,遇到状态重复时就可以将两个
s
t
e
p
step
step 加到一起,合并在一个空间内。此时剪枝就可以改为普通宽度优先搜索的剪枝(因为每一个点分为三种情况:
1.第一次到达,单独占用空间。
2.步数消耗一样小合并状态。
3.步数消耗大,剪掉。)
#include <bits/stdc++.h>
#define int long long
#define inf 1000000007
using namespace std;
int n,m,dp[1010][1010],dx[4]={0,1,0,-1},dy[4]={1,0,-1,0},num=LONG_LONG_MAX,ans,vh[1010][1010];
char a[1010][1010];
struct nod{
int x,y,pos,step;
}q[1000010];
void bfs(){
int head=1,tail=2;
q[1].x=1,q[1].y=1,q[1].pos=0,q[1].step=1;
while(head<tail){
if(q[head].x==n&&q[head].y==m&&q[head].pos<=num){
num=q[head].pos;
ans=(ans+q[head].step)%inf;
}
int x=q[head].x,y=q[head].y;
if(q[head].pos<num)
for(int i=0;i<4;++i){
int xx=x+dx[i],yy=y+dy[i];
if(xx>0&&xx<=n&&yy>0&&yy<=m&&(dp[xx][yy]==-1||dp[xx][yy]==q[head].pos+1)&&a[xx][yy]=='.'){
if(dp[xx][yy]==q[head].pos+1)q[vh[xx][yy]].step=(q[vh[xx][yy]].step+q[head].step)%inf;
else{
vh[xx][yy]=tail;
q[tail].x=xx,q[tail].y=yy,q[tail].pos=q[head].pos+1,q[tail].step=q[head].step;
dp[xx][yy]=q[tail].pos;
++tail;
}
}
}
++head;
}
}
signed main(){
memset(dp,-1,sizeof(dp));
cin>>n>>m;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
cin>>a[i][j];
bfs();
cout<<ans<<endl;
return 0;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。