2074 营救

9 篇文章 0 订阅
5 篇文章 0 订阅

大水题
就是双优先级Spfa加图论建边
说的感觉好高大上啊~
有个神奇的PPT
https://yunpan.cn/ckDHaKvcxV4ne 访问密码 5bab
题目描述 Description

在一个n*m的一个方块阵阵地上仅由楼房和街道组成,现在你在(x1,y1)点,伤员在(x2,y2)点,你可以向周围的8个方向移动,也可以爬上一部分楼房。而伤员因为受了伤,动弹不得,你必须背他回来。因此你所最担心的不是你的路程长短,而是你在救援中费的力气的大小。你爬上一幢高为H的楼房,或者从高为H的楼房房顶下来,都需要花费H的力气,而没有高度落差的行走是不费力的。现在你要完成救援的任务,最少要花费多少力气呢?费力最小的情况下,你最少又要走多少路呢?这里上、下楼不算走路。

输入描述 Input Description

输入文件的第1行有两个正整数n,m(n,m<=500),第2,3行分别是(x1,y1),(x2,y2)(1<=x1,x2<=n,1<=y1,y2<=m)。接下来有n行,每行m个数,第I行,第J列为1表示此处为空地,为2表示此处为房顶,为0表示此处无法攀爬。保证起点,终点不在0上,你可以假设可攀爬的楼房高度都为1。你到了(x2,y2)就表示救援成功。

输出描述 Output Description

输出文件包括两个在一行的数x,y,用一个空格隔开。X表示费力最少的情况下,路径的最短长度,Y表示最少花费的力气量。若无法完成营救任务,则输出’0 0’(引号不输出)。

样例输入 Sample Input

3 7
1 1
3 7
2100212
2121010
2221012

样例输出 Sample Output

8 4

数据范围及提示 Data Size & Hint

30%的数据满足:n,m<=10
100%的数据满足:n,m<=500

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
    int x,y,c,next;
}a[21000000];int len,first[2500000];
bool v[2500000];
int dx[9]={0,1,-1,0,0,-1,-1,1,1};
int dy[9]={0,0,0,-1,1,-1,1,-1,1};
int n,m,stx,sty,edx,edy,d[2500000],dd[2500000],head,tail,list[2500000],map[510][510];
void ins(int x,int y,int c){
    len++;
    a[len].x=x;a[len].y=y;a[len].c=c;
    a[len].next=first[x];first[x]=len;
}
void spfa(int st,int ed){
    memset(v,false,sizeof(v));v[st]=true;
    memset(d,63,sizeof(d));d[st]=0;d[ed]=999999999;
    memset(dd,63,sizeof(dd));dd[st]=0;dd[ed]=999999999;
    head=1;tail=2;list[head]=st;
    while(head!=tail){
        int x=list[head];
        for(int k=first[x];k>0;k=a[k].next){
            int y=a[k].y;
            if(d[y]>=d[x]+a[k].c){
                if(d[y]==d[x]+a[k].c){
                    if(dd[y]>dd[x]+1){
                        dd[y]=dd[x]+1;
                        if(v[y]==false){
                            v[y]=true;
                            list[tail++]=y;if(tail==n*m+1)tail=1;
                        }
                    }
                }
                else{
                    d[y]=d[x]+a[k].c;
                    dd[y]=dd[x]+1;
                    if(v[y]==false){
                        v[y]=true;
                        list[tail++]=y;if(tail==n*m+1)tail=1;
                    }
                }
            }
        }
        v[x]=false;
        head++;if(head==n*m+1)head=1;
    }
}
int main(){
    scanf("%d%d",&n,&m);
    scanf("%d%d%d%d",&stx,&sty,&edx,&edy);
    char s[510];
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        for(int j=1;j<=m;j++){
            map[i][j]=s[j]-'0';
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(map[i][j]==0)continue;
            for(int k=1;k<=8;k++){
                int fx=i+dx[k],fy=j+dy[k];
                if(fx>=1&&fx<=n&&fy>=1&&fy<=m&&map[fx][fy]!=0){
                    ins((i-1)*m+j,(fx-1)*m+fy,abs(map[i][j]-map[fx][fy]));
                }
            }
        }
    }
    spfa((stx-1)*m+sty,(edx-1)*m+edy);
    if(d[(edx-1)*m+edy]==999999999)printf("0 0\n");
    else printf("%d %d\n",dd[(edx-1)*m+edy]+1,d[(edx-1)*m+edy]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值