1632: [Usaco2007 Feb]Lilypad Pond
Time Limit: 5 Sec
Memory Limit: 64 MB
Submit: 450
Solved: 133
[ Submit][ Status][ Discuss]
Description
Farmer John 建造了一个美丽的池塘,用于让他的牛们审美和锻炼。这个长方形的池子被分割成了 M 行和 N 列( 1 ≤ M ≤ 30 ; 1 ≤ N ≤ 30 ) 正方形格子的 。某些格子上有惊人的坚固的莲花,还有一些岩石,其余的只是美丽,纯净,湛蓝的水。 贝茜正在练习芭蕾舞,她从一个莲花跳跃到另一个莲花,当前位于一个莲花。她希望在莲花上一个一个的跳,目标是另一个给定莲花。她能跳既不入水,也不到一个岩石上。 令门外汉惊讶的是,贝茜的每次的跳跃像中国象棋的马一样:横向移动1,纵向移动2,或纵向移动1,横向移动2。贝茜有时可能会有多达8个选择的跳跃。 Farmer John 在观察贝茜的芭蕾舞联系,他意识到有时候贝茜有可能跳不到她想去的目的地,因为路上有些地方没有莲花。于是他想要添加几个莲花使贝茜能够完成任务。一贯节俭的Farmer John想添加最少数量的莲花。当然,莲花不能放在石头上。 请帮助Farmer John确定必须要添加的莲花的最少数量。在添加的莲花最少基础上,算出贝茜从起始点跳到目标点需要的最少的步数。最后,还要算出满足添加的莲花的最少数量时,跳跃最少步数的跳跃路径的条数。
Input
第 1 行: 两个整数 M , N
第 2..M + 1 行:第 i + 1 行,第 i + 1 行 有 N 个整数,表示该位置的状态: 0 为水; 1 为莲花; 2 为岩石; 3 为贝茜开始的位置; 4 为贝茜要去的目标位置.
Output
第 1 行: 一个整数: 需要添加的最少的莲花数. 如果无论如何贝茜也无法跳到,输出 -1.
第 2 行: 一个整数: 在添加的莲花最少基础上,贝茜从起始点跳到目标点需要的最少的步数。如果第1行输出-1,这行不输出。 第 3 行: 一个整数: 添加的莲花的最少数量时,跳跃步数为第2行输出的值的跳跃路径的条数 如果第1行输出-1,这行不输出。
Sample Input
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
Sample Output
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
这题一开始居然企图二分+四维dp(hehehehehehe)
结果发现原来SPFA可以满足好多关键字的最短路。。
于是在结构体里Add表示需要增加的荷叶数,step代表需要走的步数,num代表方案数
优先级Add>step。。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<cstdlib>
#include<map>
#include<cmath>
using namespace std;
const int maxn = 50;
const int dx[8] = {1,1,2,2,-1,-1,-2,-2};
const int dy[8] = {2,-2,1,-1,2,-2,1,-1};
struct P{
int x,y;
}S,T;
struct F{
int Add,step;
long long num;
}f[maxn][maxn];
int n,i,j,m,p[maxn][maxn];
bool vis[maxn][maxn];
queue <P> q;
int main()
{
#ifndef ONLINE_JUDGE
#ifndef YZY
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#else
freopen("yzy.txt","r",stdin);
#endif
#endif
cin >> n >> m;
for (i = 1; i <= n; i++)
for (j = 1; j <= m; j++)
{
scanf("%d",&p[i][j]);
f[i][j].Add = f[i][j].step = 1e9;
if (p[i][j] == 3)
{
f[i][j].step = f[i][j].Add = 0;
f[i][j].num = 1;
S.x = i;
S.y = j;
}
if (p[i][j] == 4) T.x = i,T.y = j;
}
memset(vis,false,sizeof(vis));
vis[S.x][S.y] = true;
q.push(S);
while (!q.empty())
{
P k = q.front();
q.pop();
if (p[k.x][k.y] == 4) continue;
vis[k.x][k.y] = false;
for (int l = 0; l < 8; l++)
{
int xx = k.x + dx[l];
int yy = k.y + dy[l];
if (xx < 1 || xx > n || yy < 1 || yy > m || p[xx][yy] == 2) continue;
int A = (p[xx][yy] == 0);
if (f[xx][yy].Add > f[k.x][k.y].Add + A)
{
f[xx][yy].Add = f[k.x][k.y].Add + A;
f[xx][yy].step = f[k.x][k.y].step + 1;
f[xx][yy].num = f[k.x][k.y].num;
if (!vis[xx][yy])
{
vis[xx][yy] = true;
q.push((P){xx,yy});
}
continue;
}
if (f[xx][yy].Add == f[k.x][k.y].Add + A)
{
if (f[xx][yy].step > f[k.x][k.y].step + 1)
{
f[xx][yy].step = f[k.x][k.y].step + 1;
f[xx][yy].num = f[k.x][k.y].num;
if (!vis[xx][yy])
{
vis[xx][yy] = true;
q.push((P){xx,yy});
}
continue;
}
if (f[xx][yy].step == f[k.x][k.y].step + 1)
{
f[xx][yy].num += f[k.x][k.y].num;
if (!vis[xx][yy])
{
vis[xx][yy] = true;
q.push((P){xx,yy});
}
}
}
}
}
if (f[T.x][T.y].Add > n * m)
{
cout << -1;
return 0;
}
printf("%d\n%d\n%lld",f[T.x][T.y].Add,f[T.x][T.y].step,f[T.x][T.y].num);
return 0;
}