题目描述
小菡很聪明,所以他打ACM非常给力,经常偷偷学习到深夜
他是如此的努力学习,以至于他根本就没有时间完整的逛过学校。
有一天,他听说科大湖的黑天鹅非常好看,由于没有女朋友,他便独自一个人去了。
然而他还在专心致志的观赏黑天鹅,丝毫没有意识到集训还有 k 分钟就要开始了,不幸的是刚好小菡是一个路痴。
你觉得他在 k 分钟内可以赶到创客参加集训吗?
如果可以,他最少要花多少时间才可以回到创客空间参加集训呢?这样子的路径有多少条?
输入
测试数据第一组为T(1 <= T <= 100),表示测试样例组数。
对于每组测试样例:
第一行输入为三个正整数 n m k(1 <= n,m <= 1000,0 <= k <= 10000),n,m表示地图的长和宽,k表示最多允许花费在路上的时间(在路上花费的时间刚好为k也合法)。
接下来n行输入地图,其中包含有符号‘*’、‘#’、‘L’、‘C’。
*:表示可以允许走动的空间。
#:表示障碍物,无法走动的空间。
L:表示科大湖,即小菡的起点,保证有且仅有一个。
C:表示创客空间,即小菡的终点,保证有且仅有一个。
小菡走动的计时是从一个空间到另一个空间为一分钟。开始时,小菡已经站在了起点上。当移动时间等于k时刚好到达终点依然视为合法。
(注意:小菡只能往上下左右四个方向走动。)
输出
输出形式为“Case #x: ”(不包含引号),x表示对应第x个样例。
如果小菡在 k 分钟内无法回到创客,则输出-1。
否则,输出小菡回到创客花费的最短时间,和满足该最短时间的路径条数。
样例输入
4
2 2 3
L*
C
4 4 10
L**
C
4 4 8
L##
#*
###*
C***
4 4 10
L*##
#***
###*
C***
样例输出
Case #1: 2 2
Case #2: 6 20
Case #3: -1
Case #4: 9 1
题意
求最短路径方案数
思路:
①求最短路可以用bfs(),但要求方案数(存在不同的路径到达同一点,且所花时间相同且最短),考虑花费为相同的一层遍历要完全走完,并且记录走了几圈,也就是花了多少时间。
对于走过的点不能立即标记为访问过,而是出队后再标记为访问过,因为bfs()是一圈一圈的往外走,每一圈可以对应成一个时间,这一圈所花的时间是上一圈的时间+1。如果上一圈的下一步没有全部走完,这个点可能会被上一圈再次走到,所以不能立即 标记为不能再走,防止一个点退回上一圈,所以当点所在圈已经走完,它的上一圈没必要再走一次,也就是每个点出队后就可以把它标记为访问过(不让它再被入队)。
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char graph[1020][1020];//图
int visited[1020][1020];//记录所需时间
int MOVE[4][2] ={
{
-1,0},{
1,0},{
0,1},{
0,-1}};
ll n,m,k;
ll ans;
struct point{
//点的坐标
int x,y;
};
bool right_index(int i,int j){
//判断下标合法性
return 0 <= i && i < n && 0 <= j && j < m;
}
int bfs(int i,int j){
//从起点开始一圈一圈的往外扩张,外圈所花时间比里圈多1
queue<point>q;
point u,v;
u.x = i;
u.y = j;
q.push(u);
int cnt = 0;
int x1,y1;
while(!q.empty() && cnt < k){
u = q.front();
q.pop();
//cout << u.x << ' ' << u.y << endl;
for(int i = 0;i < 4;i++){
v.x = u.x + MOVE[i][0];
v.y = u.y + MOVE[i][1];
if(right_index(v.x,v.y)){
if(graph[v.x][v.y] == '*'){
q.push(v);
visited[v.x][v.y] = visited[u.x][u.y] + 1;
}else if(graph[v.x][v.y] == 'C'){
visited[v.x][v.y] = visited[u.x][u.y] + 1;
ans++;
x1 = v.x;//记录创客坐标
y1 = v.y;
}
}
}
graph[u.x][u.y] = '#'; //剪枝 已经开始走u的下一圈,防止点u再走
if(!q.empty()){
v = q.front();
if(visited[u.x][u.y] != visited[v.x][v.y]){
//如果点u和下一个点
cnt++; //到达的所需时间不同就说明
} //说明上个点是它那个圈的最后一个点
}
}
if(ans)//如果找到路径 返回所需最短时间
return visited[x1][y1];
else return 0;
}
int main(){
int T;
int flag = 0;
cin >> T;
for(int t = 0;t < T;t++){
ans = flag = 0;
memset(graph,0,sizeof(graph));
memset(visited,0,sizeof(visited));
scanf("%d %d %d",&n,&m,&k);
for(int i = 0;i < n;i++){
scanf("%s",graph[i]);
//cout << graph[i] << endl;
}
for(int i = 0;i < n;i++){
for(int j = 0;j < m;j++){
if(graph[i][j] =='L'){
//找起点
k = bfs(i,j);
flag = 1;
break;
}
}
if(flag)
break;
}
if(ans)
printf("Case #%d: %d %d\n",t+1,k,ans);
else printf("Case #%d: -1\n",t+1);
}
//system("pause");
return 0;
}
②可以用dfs()记忆化搜索 + 3个剪枝 (代码中有)
对一个点进行深搜前要将其标记为走过,防止两个点来回走死循环,对一个点深搜后,要把这个点再标记为没走过,因为别的搜索方案可能到这个点花的时间可以更少。
AC代码
#include <bits/stdc++.h>
using namespace std;
char path[1010][1010];
int visited[1010][1010];
int MOVE[4][2] = {
{
-1,0},{
1,0},{
0,-1},{
0,1}};
int T,n,m,k;
int ans;
int x,y; //记录创客坐标
int flag1,flag; //flag1记录是否已经早到最短路径
bool right_index(int i,int j){
return 0 <= i && i < n && 0 <= j && j < m;
}
void dfs(int i,int j,int time){
// 坐标 和已经使用的时间
int i1,j1;
if(time > k)//剪枝
return ;
if(visited[i][j] && visited[i][j] < time)//剪枝
return ;
visited[i][j] = time;
if(flag1 && k-time < abs(x-i) + abs(y-j))//剪枝
return ;
if(path[i][j] == 'C'){
if(time == k){
ans++;
}
else{
//time < k
ans = 1;
k = time;//更新最短距离
}
x = i;
y = j;
flag1 = 1; //标记已经有了最短路径
return ;
}
path[i][j] = '#';//把走过的路标记
for(int g = 0;g < 4;g++){
i1 = i + MOVE[g][0];
j1 = j + MOVE[g][1];
if(right_index(i1,j1) && path[i1][j1] != '#'){
dfs(i1,j1,time + 1);
}
}
path[i][j] = '*';//退回上一步,所以标记为没有走过
return ;
}
int main(){
cin >> T;
for(int t = 0;t < T;t++){
memset(visited,0,sizeof(visited));
ans = 0;
cin >> n >> m >> k;
for(int i = 0;i < n;i++){
scanf("%s",path[i]);
}
flag1 = 0;
flag = 0;
for(int i = 0;i < n;i++){
for(int j = 0;j < m;j++)
if(path[i][j] == 'L'){
dfs(i,j,0);
if(ans)
cout << "Case #"<< t+1 <<": " << k << " " << ans << " " << endl;
else cout << "Case #"<< t+1 <<": " << -1 << endl;
flag = 1;
break;
}
if(flag)
break;
}
}
//system("pause");
return 0;
}