USACO 黄金莲花池 BFS

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39439314/article/details/77512420

【问题描述】

   FJ建造了一个美丽的池塘,用于让奶牛们锻炼。这个长方形的池子被分割成了 M 行和 N 列(正方形格子的 。某些格子上有莲花,还有一些岩石,其余的只是美丽,纯净,湛蓝的水。
   贝茜正在练习芭蕾舞,她从一个莲花跳跃到另一个莲花,当前位于一个莲花。她希望在莲花上一个一个的跳,目标是另一个给定莲花。她不能跳入水中,也不能跳到岩石上。贝茜的每次的跳跃像国际象棋中的骑士一样:横向移动1,纵向移动2,或纵向移动1,横向移动2。所以贝茜有时可能会有多达8个选择的跳跃。
   FJ在观察贝茜的芭蕾舞,他意识到有时候贝茜有可能跳不到她想去的目的地,因为路上有些地方没有莲花。于是他想要添加几个莲花使贝茜能够完成任务。一贯节俭的FJ想添加最少数量的莲花。当然,莲花不能放在石头上。
   帮助FJ确定必须要添加的莲花的最少数量,和他一共有多少种不同放置莲花的方案。

【输入格式】

  第1行: 两个整数M,N。
  第2..M+1行:第i+1行,第i+1行 有N个整数,表示该位置的状态: 0 为水; 1 为莲花; 2 为岩石; 3 为贝茜开始的位置; 4 为贝茜要去的目标位置.

【输出格式】
   第1行: 一个整数: 需要添加的最少的莲花数. 如果无论如何贝茜也无法跳到,输出-1.
   第2行: 一个整数: 表示放置荷叶的方案数,如果第1行输出-1,这行不输出。

【输入样例】

4 5
1 0 0 0 0
3 0 0 0 0
0 0 2 0 0
0 0 0 4 0

【输出样例】

2
3

【样例解释】

  至少要增加 2 片荷叶,一共有3种摆放方法:
   方法1       方法2      方法3
  R1C2,R2C3    R1C3,R3C2    R1C3,R2C5

  1 0 0 0 0    1 0 X 0 0    1 0 X 0 0
  3 0 X 0 0    3 0 0 0 0    3 0 0 0 X
  0 0 2 0 0    0 X 2 0 0    0 0 2 0 0
  0 X 0 4 0    0 0 0 4 0    0 0 0 4 0

【数据范围】

1 ≤ M ≤ 30
1 ≤ N ≤ 30

——————————————————————————————————————————

前两个池子就不说了,学了BFS都会做。这个金池子比较有意思,大概一个月之前做了一次没有AC,这遍终于过了。

说说思路。先看怎么算路径长度,实际上莲花只是存在于水上,那么就只在贝茜经过水的时候把路径长度+1就可以计算路径长度了。关键是有一个方案数的问题,如果直接就像这样在计算dist的同时计算方案数的话会很容易发生重复计算路径的情况,比如从两朵莲花可以跳到同一片水上,这个时候莲花还是放在这个位置,不可以算作不同的方案。

怎么办呢?可以这样做:把从一些格子(贝茜的起点和水)开始加一朵莲花就可以到达的格子全部计算出来(DFS写起来方便),重新建成一张图,然后就可以在这张图上面进行裸BFS就行了。注意方案数要开long long,方案数毕竟是方案数啊!

终于结束了历时一个月的和池子的战斗!!!

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#define inf 1005
using namespace std;
const int maxn=35; 
typedef long long LL;

int M,N,A[maxn][maxn];
struct XY{ int x,y; }S,T;
int dx[]={-2,-1,1,2,2,1,-1,-2},dy[]={-1,-2,-2,-1,1,2,2,1};
int dist[maxn][maxn];
LL sum[maxn][maxn];
bool vis[maxn][maxn];
vector<XY>E[maxn][maxn];

void data_in()
{
    scanf("%d%d",&M,&N);
    for(int i=1;i<=M;i++)
    for(int j=1;j<=N;j++)
    {
        scanf("%d",&A[i][j]);
        if(A[i][j]==3) S=(XY){i,j};
        if(A[i][j]==4) T=(XY){i,j};
    }
}
void add_edge(int a,int b,int x,int y)
{
    E[a][b].push_back((XY){x,y});
}
void DFS(int X,int Y,int x,int y,int w)
{
    vis[x][y]=1;
    if(w>=1)
    {
        add_edge(X,Y,x,y);
        return;
    }
    int xx,yy;
    for(int k=0;k<8;k++)
    {
        xx=x+dx[k],yy=y+dy[k];
        if(xx<1 || xx>M || yy<1 || yy>N) continue;
        if(vis[xx][yy]) continue;
        if(A[xx][yy]==2) continue;
        if(A[xx][yy]==1) DFS(X,Y,xx,yy,w);
        else DFS(X,Y,xx,yy,w+1);
    }
}
void set_gragh()
{
    for(int i=1;i<=M;i++)
    for(int j=1;j<=N;j++)
        if(A[i][j]==3 || A[i][j]==0)
        {
            memset(vis,0,sizeof(vis));
            DFS(i,j,i,j,0);
        }
}
void BFS(XY s)
{
    memset(dist,0,sizeof(dist));
    queue<XY>q;
    dist[s.x][s.y]=0;
    sum[s.x][s.y]=1;
    q.push(s);
    int x,y,xx,yy;
    XY tmp;
    while(!q.empty())
    {
        tmp=q.front();q.pop();
        x=tmp.x,y=tmp.y;
        int n=E[x][y].size();
        for(int i=0;i<n;i++)
        {
            xx=E[x][y][i].x,yy=E[x][y][i].y;
            if(dist[xx][yy])
            {
                if(dist[xx][yy]==dist[x][y]+1)
                    sum[xx][yy]+=sum[x][y];
                continue;
            }
            dist[xx][yy]=dist[x][y]+1;
            sum[xx][yy]=sum[x][y];
            q.push((XY){xx,yy});
        }
    }
}
void work()
{
    set_gragh(); 
    BFS(S);
    if(dist[T.x][T.y]==0) printf("-1\n");
    else cout<<dist[T.x][T.y]-1<<endl<<sum[T.x][T.y]<<endl;
}
int main()
{
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
    data_in();
    work(); 
    return 0;
}
阅读更多
换一批

没有更多推荐了,返回首页