bzoj 1671: [Usaco2005 Dec]Knights of Ni 骑士

题目链接


题目背景:

贝茜遇到了一件很麻烦的事:她无意中闯入了森林里的一座城堡,如果她想回家,就必须穿过这片由骑士们守护着的森林.为了能安全地离开,贝茜不得不按照骑士们的要求,在森林寻找一种特殊的灌木并带一棵给他们.当然,贝茜想早点离开这可怕的森林,于是她必须尽快完成骑士们给的任务,贝茜随身带着这片森林的地图,地图上的森林被放入了直角坐标系,并按x,y轴上的单位长度划分成了W×H(1≤W,H≤1000)块,贝茜在地图上查出了她自己以及骑士们所在的位置,当然地图上也标注了她所需要的灌木生长的区域.某些区域是不能通过的(比如说沼泽地,悬崖,以及食人兔的聚居地).在没有找到灌木之前,贝茜不能通过骑士们所在的那个区域,为了确保她自己不会迷路,贝茜只向正北、正东、正南、正西四个方向移动(注意,她不会走对角线).她要走整整一天,才能从某块区域走到与它相邻的那块区域.    输入数据保证贝茜一定能完成骑士的任务.贝茜希望你能帮她计算一下,她最少需要多少天才可脱离这可怕的地方?


题目大意:

一个w*h的矩阵,有不能到达的点,从起点经过多个中间点其中的一个然后到达终点的最短路


注意事项:

只有一个起点和一个终点,也就是说"骑士们"其实只有一个


题解:

我看其他的博客有用两遍dfs然后遍历所有点相加的。。。

然而当时我都写完代码了,正在调,感觉那个方法好机智啊qwq


我是正常跑spfa,然后维护最短路的数组开两维,一个是捡到灌木之前的,一个是之后的

具体看代码吧


#include<iostream>
#include<cstdio>
#include<queue>
 
#define inf 10000000
 
using namespace std;
 
struct point{
    int x,y;
    friend bool operator == (point a,point b){
        if(a.x==b.x && a.y==b.y)return true;
        else return false;
    }
};
 
struct node{
    bool guan;
    point now;
    int num;
    friend bool operator < (node a,node b){
        return a.num>b.num;
    }
};
 
int tox[4]={-1,0,1,0};
int toy[4]={0,1,0,-1};
point s,t;
int n,m;
int a[1010][1010];
int Min[1010][1010][2];
priority_queue<node>q;
 
int main(){
    scanf("%d%d",&m,&n);
    for(int i=1; i<=n; i++){
        for(int j=1; j<=m; j++){
            scanf("%d",&a[i][j]);
            if(a[i][j]==2)s.x=i,s.y=j;
            if(a[i][j]==3)t.x=i,t.y=j;
            Min[i][j][0]=Min[i][j][1]=inf;
        }
    }
    node tt;
    tt.guan=false;
    tt.now=s;
    Min[s.x][s.y][0]=0;
    tt.num=0;
    q.push(tt);
    while(!q.empty()){
        tt=q.top();
        q.pop();
        if(tt.guan && tt.now==t){
            break;
        }
        for(int i=0; i<4; i++){
            node t1=tt;
            t1.now.x+=tox[i];
            t1.now.y+=toy[i];
            if(t1.now.x<1 || t1.now.x>n || t1.now.y<1 || t1.now.y>m)continue;
            if(a[t1.now.x][t1.now.y]==1)continue;
            if(Min[t1.now.x][t1.now.y][t1.guan]<=t1.num+1)continue;
            Min[t1.now.x][t1.now.y][t1.guan]=t1.num+1;
            if(t1.guan==false && a[t1.now.x][t1.now.y]==4){
                t1.guan=true;
                Min[t1.now.x][t1.now.y][t1.guan]=Min[t1.now.x][t1.now.y][0];
            }
            t1.num++;
            q.push(t1);
        }
    }
    printf("%d\n",tt.num);
     
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值