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

题目描述

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

数据范围

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

解法

SPFA。

代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define ll long long
using namespace std;
const char* fin="lilypad.in";
const char* fout="lilypad.out";
const int inf=0x7fffffff;
const int maxn=107,maxtot=10007,maxm=17;
const int w[8][2]={{2,1},{1,2},{-1,2},{2,-1},{-1,-2},{-2,-1},{-2,1},{1,-2}};
int n,m,i,j,k,ans,sx,sy,tx,ty;
int a[maxn][maxn];
int f[maxn][maxn],g[maxn][maxn];
int b[maxn*maxn*maxm][2],head,tail;
bool bz[maxn][maxn];
void add(int x,int y,int z,int d){
    if (x>0 && x<=n && y>0 && y<=m && a[x][y]!=2){
        if (a[x][y]==0) z++;
        if (z>f[x][y] || z==f[x][y] && d>g[x][y]) return;
        f[x][y]=z;
        g[x][y]=d;
        if (!bz[x][y]){
            b[++tail][0]=x;
            b[tail][1]=y;
            bz[x][y]=true;
        }
    }
}
void spfa(){
    int i,j,k,xx,yy,nx,ny;
    head=tail=0;
    add(sx,sy,0,0);
    while (head++<tail){
        xx=b[head][0];
        yy=b[head][1];
        for (i=0;i<8;i++){
            add(xx+w[i][0],yy+w[i][1],f[xx][yy],g[xx][yy]+1);
        }
        bz[xx][yy]=false;
    }
}
int main(){
    freopen(fin,"r",stdin);
    freopen(fout,"w",stdout);
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++) for (j=1;j<=m;j++){
        scanf("%d",&a[i][j]);
        if (a[i][j]==3) sx=i,sy=j;
        if (a[i][j]==4) tx=i,ty=j;
    }
    memset(f,127,sizeof(f));
    memset(g,127,sizeof(g));
    spfa();
    if (f[tx][ty]<2000000000) printf("%d %d",f[tx][ty],g[tx][ty]);
    else printf("-1 -1");
    return 0;
}

启发

SPFA的关系式只要是二元关系即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值