JZOJ4855. 【NOIP2016提高A组集训第6场11.3】荷花池塘

17 篇文章 0 订阅

Description

于大夫建造了一个美丽的池塘,用来让自己愉快的玩耍。这个长方形的池子被分割成了M 行和N 列的正方形格子。池塘中有些地方是可以跳上的荷叶,有些地方是不能放置荷叶也不能跳上的岩石,其他地方是池水(当然于大夫也是不能游泳的)。于大夫十分有趣,他在池塘跳跃的方式和象棋中的马一样可以向八个方向走日字形,而且于大夫只能跳上荷叶。于大夫每天从一个给定的有荷叶的地方出发,试图到达另一个给定的有荷叶的地方。但有一天他发现自己无论如何也不能到达目的地了,除非再在水中放置几个荷叶。于大夫想让你告诉他,最少还需放置几片荷叶?在放置荷叶最少的前提下,最少需要几步能到达目的地?

Data Constraint

10%的数据n,m<=4
30%的数据n,m<=10
50%的数据n,m<=30
70%的数据n,m<=50
100%的数据n,m<=100

Solution

其实这道题目就是要你在跳跃荷叶最少的情况下求最短路。不难发现,其实荷叶最少也是在求最短路。所以题目变成求一条以荷叶为第一关键字,走的步数为第二关键字的最短路。用spfa跑一下即可(和正常的只有一个关键字的spfa类似)。

具体做法为:我们设F[i][j]为到达(i,j)所需的最少荷叶数量,G[i][j]表示在到达(i,j)所需的最少荷叶数量的情况下,所需的最少步数。那么对于一个点X,他假设能更新另一个点Y的F值,那么就将更新的点Y加入队列,另外,这个点X的F值和点Y的F值相同,但点X的G值能更新点Y的G值,那么同样将点Y加入队列

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=105;
const int c[8][2]={{2,1},{1,2},{2,-1},{-1,2},{-2,1},{1,-2},{-1,-2},{-2,-1}};
int f[maxn][maxn],g[maxn][maxn],v[maxn*maxn*maxn][2],a[maxn][maxn];
int n,i,t,j,k,l,x,m,y,xx,yy,ex,ey,p;
bool bz[maxn][maxn];
int main(){
    freopen("lilypad.in","r",stdin);freopen("lilypad.out","w",stdout);
    scanf("%d%d",&n,&m);memset(f,127,sizeof(f));
    p=f[1][1];
    for (i=1;i<=n;i++)
        for (j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
            if (a[i][j]==3)v[1][0]=i,v[1][1]=j,bz[i][j]=true,f[i][j]=0;
            else if (a[i][j]==4) ex=i,ey=j;
            if (a[i][j]>2) a[i][j]=1;
        }
    j=1;i=0;
    while (i<j){
        xx=v[++i][0];yy=v[i][1];
        for (k=0;k<8;k++){
            x=xx+c[k][0];y=yy+c[k][1];
            if (x<1 || y<1 || x>n || y>m || a[x][y]>1) continue;
            if (!a[x][y]) t=f[xx][yy]+1;
            else t=f[xx][yy];
            if (f[x][y]>t || f[x][y]==t && g[xx][yy]+1<g[x][y]){
                f[x][y]=t,g[x][y]=g[xx][yy]+1;
                if (bz[x][y]) continue;
                bz[x][y]=true;v[++j][0]=x;v[j][1]=y;
            }
        }
        bz[xx][yy]=false;
    }
    if (f[ex][ey]!=p) printf("%d %d\n",f[ex][ey],g[ex][ey]);
    else printf("-1 -1\n");
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值