[USACO Feb07] 银色莲花池
时间限制:1 s 内存限制:64 MB
译 By CmYkRgB123
描述
Farmer John 建造了一个美丽的池塘,用于让他的牛们审美和锻炼。这个长方形的池子被分割成了 M 行和 N 列( 1 ≤ M ≤ 30 ; 1 ≤ N ≤ 30 ) 正方形格子的 。某些格子上有惊人的坚固的莲花,还有一些岩石,其余的只是美丽,纯净,湛蓝的水。
贝茜正在练习芭蕾舞,她从一个莲花跳跃到另一个莲花,当前位于一个莲花。她希望在莲花上一个一个的跳,目标是另一个给定莲花。她能跳既不入水,也不到一个岩石上。
令门外汉惊讶的是,贝茜的每次的跳跃像国际象棋中的骑士一样:横向移动1,纵向移动2,或纵向移动,横向移动2。贝茜有时可能会有多达8个选择的跳跃。
Farmer John 在观察贝茜的芭蕾舞联系,他意识到有时候贝茜有可能跳不到她想去的目的地,因为路上有些地方没有莲花。于是他想要添加几个莲花使贝茜能够完成任务。一贯节俭的Farmer John想添加最少数量的莲花。当然,莲花不能放在石头上。
请帮助Farmer John确定必须要添加的莲花的最少数量。在添加的莲花最少基础上,算出贝茜从起始点跳到目标点需要的最少的步数。最后,还要算出满足添加的莲花的最少数量时,跳跃最少步数的跳跃路径的条数。
输入
第 1 行: 两个整数 M , N
第 2..M + 1 行:第 i + 1 行,第 i + 1 行 有 N 个整数,表示该位置的状态: 0 为水; 1 为莲花; 2 为岩石; 3 为贝茜开始的位置; 4 为贝茜要去的目标位置.
输出
第 1 行: 一个整数: 需要添加的最少的莲花数. 如果无论如何贝茜也无法跳到,输出 -1.
第 2 行: 一个整数: 在添加的莲花最少基础上,贝茜从起始点跳到目标点需要的最少的步数。如果第1行输出-1,这行不输出。
第 3 行: 一个整数: 添加的莲花的最少数量时,跳跃步数为第2行输出的值的跳跃路径的条数 如果第1行输出-1,这行不输出。
样例输入
4 8
0 0 0 1 0 0 0 0
0 0 0 0 0 2 0 1
0 0 0 0 0 4 0 0
3 0 0 0 0 0 1 0
样例输出
2
6
2
输出说明
至少要添加2朵莲花,放在了’x’的位置。
0 0 0 1 0 0 0 0…0 0 0 1 0 0 0 0
0 x 0 0 0 2 0 1…0 0 0 0 0 2 0 1
0 0 0 0 x 4 0 0…0 0 x 0 x 4 0 0
3 0 0 0 0 0 1 0…3 0 0 0 0 0 1 0
贝茜至少要条6步,有以下两种方案
0 0 0 C 0 0 0 0…0 0 0 C 0 0 0 0
0 B 0 0 0 2 0 F…0 0 0 0 0 2 0 F
0 0 0 0 D G 0 0…0 0 B 0 D G 0 0
A 0 0 0 0 0 E 0…A 0 0 0 0 0 E 0
一道极品搜索题,以后对搜索生疏的时候可以拿来练手QAQ
/*
Name: 银色莲花池
Date: 14/10/16 07:42
Description:
前两问很好解决 一遍宽搜可以很好的解决问题
但是关键在第三问 要求输出方案(记住这一个教训方案数很可能需要开longlong甚至是写高精度)
开始时想的是一遍宽搜跑出答案但这显然不现实 因为vis数组会很好的帮你去重
于是又想到了用一个f[x][y][step][ned]表示在一个点用step步 添加ned荷叶的方案数虽然这可以很好的
计算所有情况,但是也很好的超过了内存限制,迫不得已看了一下题解 -_-|||
由于是最短距离到达终点 所以我们可以用 dis[x][y][ned] 表示用ned荷叶到达(x,y) 所用的最短距离
way[x][y][ned] 表示方案数 于是乎得出了答案
*/
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 35
#define maxm maxn*maxn
#define LL long long
#define inf 0x7f7f7f7f
LL n,m,ans=inf,num=inf,cnt,a[maxn][maxn],startx,starty,endx,endy;
LL st[8][2]={{-2,1},{-1,2},{2,1},{1,2},{-2,-1},{-1,-2},{1,-2},{2,-1}};
struct Node{
LL x,y,step,ned;
Node(LL A,LL B,LL C,LL D){
x=A,y=B,step=C,ned=D;
}
};
queue<Node> q;
bool vis[maxn][maxn][maxm],Check;
LL dis[maxn][maxn][maxm],way[maxn][maxn][maxm];
void Bfs(){
while( !q.empty() ){
Node temp=q.front(); q.pop();
if(temp.ned>num) continue;
for(LL i=0;i<8;i++){
LL xx=temp.x+st[i][0],yy=temp.y+st[i][1];
if(xx<1||yy<1||xx>n||yy>m)continue;
if(a[xx][yy]==2)continue;
if(a[xx][yy]==4){
Check=1;
if(num>temp.ned){
num=temp.ned;
ans=temp.step+1;
continue;
}
if(num==temp.ned){
if(ans>temp.step+1){
ans=temp.step+1;
continue;
}
}
}
if(a[xx][yy]==1 && !vis[xx][yy][temp.ned]){
q.push(Node(xx,yy,temp.step+1,temp.ned));
vis[xx][yy][temp.ned]=1;
}
if(a[xx][yy]==0 && !vis[xx][yy][temp.ned+1] ){
q.push(Node(xx,yy,temp.step+1,temp.ned+1));
vis[xx][yy][temp.ned+1]=1;
}
}
}
if(!Check) {printf("-1\n-1\n-1\n"); exit(0);}
while( !q.empty() )q.pop();
for(LL i=1;i<=n;i++)for(LL j=1;j<=m;j++)for(LL k=0;k<=num;k++) dis[i][j][k]=inf;
memset(dis[startx][starty],0,sizeof(dis[startx][starty]));
memset(way,0,sizeof(way)); way[startx][starty][0]=1;
q.push(Node(startx,starty,0,0));
a[endx][endy]=1;
while( !q.empty() ){
Node temp=q.front();q.pop();
for(LL i=0;i<8;i++){
LL xx=temp.x+st[i][0],yy=temp.y+st[i][1];
if(xx<1||yy<1||xx>n||yy>m)continue;
if(a[xx][yy]==2)continue;
if(a[xx][yy]==1){
if(temp.step+1<=ans && temp.ned<=num){
if(temp.step+1<=dis[xx][yy][temp.ned]){
if(temp.step+1<dis[xx][yy][temp.ned]){
q.push(Node(xx,yy,temp.step+1,temp.ned));
way[xx][yy][temp.ned]=0;
}
way[xx][yy][temp.ned]+=way[temp.x][temp.y][temp.ned];
dis[xx][yy][temp.ned]=temp.step+1;
}
}
}
if(a[xx][yy]==0){
if(temp.ned+1<=num && temp.step+1<=ans){
if(temp.step+1<=dis[xx][yy][temp.ned+1]){
if(temp.step+1<dis[xx][yy][temp.ned+1]){
q.push(Node(xx,yy,temp.step+1,temp.ned+1));
way[xx][yy][temp.ned+1]=0;
}
way[xx][yy][temp.ned+1]+=way[temp.x][temp.y][temp.ned];
dis[xx][yy][temp.ned+1]=temp.step+1;
}
}
}
}
}
}
int main(){
freopen("silvlily.in","r",stdin); freopen("silvlily.out","w",stdout);
scanf("%lld%lld",&n,&m);
LL x,y;
for(LL i=1;i<=n;i++){
for(LL j=1;j<=m;j++){
scanf("%lld",&a[i][j]);
if(a[i][j]==3){
q.push(Node(i,j,0,0));
vis[i][j][0]=1; startx=i;starty=j;
}
if(a[i][j]==4){endx=i,endy=j;}
}
}
Bfs();
printf("%lld\n%lld\n%lld\n",num,ans,way[endx][endy][num]);
getchar(); getchar();
return 0;
}