Uva 1600 满足条件的最短路

原题

非常有意思的一道最短路径题. 地图中有障碍物, 障碍物可以通过, 但不能连续通过K个障碍物. 实现起来也不难, 就是在BFS的时候给结点添加一个属性来记录已连续通过的障碍物个数就行了.

比较值得注意的地方是, 如果用map存储自定义类型, 而且自定义类型中的还有多个同等重要的成员时, 重载<运算符的时候必须小心一些, 应该类似这样的形式:

friend bool operator<(const Point & p1, const Point & p2) {
    if ( p1.x != p2.x ) return p1.x < p2.x;
    else if ( p1.y != p2.y ) return p1.y < p2.y;
    else return p1.k < p2.k;
}

而不能为了简洁好看写成这样:

friend bool operator<(const Point & p1, const Point & p2) {
    return (p1.x < p2.x && p1.y < p2.y && p1.k < p2.k);
}

以上两个函数所得到的结果是完全不同的, 第二种看上去很像是可行的,
但并不是我们需要的逻辑, 设想一下就知道了 : 比如当两个点 p1, p2的x值相等时,
那么p1 < p2 和p2 < p1都会是false, 但 p1 和 p2 是不一定相等的 , 因此不能这么写

AC代码如下

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <list>
#include <cassert>
#include <iomanip>

#pragma warning(disable:4996) //关掉4996警告

/*
Uva 439 
关键 : 求最短路径 <- BFS
*/

using namespace std;

const int MAXN = 9;

struct Point {
    int y, x;
    int k;          // 当前已通过的障碍物数
    Point(int _y = 0, int _x = 0, int _k = 0): x(_x), y(_y), k(_k){}
    friend bool operator<(const Point & p1, const Point & p2) {
        if ( p1.x != p2.x ) return p1.x < p2.x;
        else if ( p1.y != p2.y ) return p1.y < p2.y;
        else return p1.k < p2.k;
    }
    friend bool operator==(const Point & p1, const Point & p2) {
        return (p1.x == p2.x && p1.y == p2.y && p1.k == p2.k);
    }
};


int  M, N, K;
int  Move[4][2] = { { 1, 0 },{ 0, 1 },{ 0, -1 },{ -1, 0 } };
bool G[21][21];

bool isAvailable(const Point & p) {
    return (p.x >= 1 && p.x <= N && p.y >= 1 && p.y <= M );
}

int BFS(const Point & Start, const Point & End) {
    Point cur;
    map<Point, int> Dis;
    map<Point, bool> isVisited;
    queue<Point> Q;
    Q.push(Start);
    Dis[Start] = 0;
    bool isFound = false;
    while ( !Q.empty() ) {
        cur = Q.front( ); Q.pop( );
        if ( cur.x == End.x && cur.y == End.y ) {
            isFound = true;
            break;
        }
        isVisited[cur] = true;
        Point next;
        for ( int i = 0; i < 4; i++ ) {
            next = Point(cur.y + Move[i][1], cur.x + Move[i][0], cur.k);
            if ( G[next.y][next.x] ) next.k++;
            else next.k = 0;
            if ( isAvailable(next) && 
                 !isVisited[next]  &&       // isVisited总返回true
                 next.k <= K ) {
                Q.push(next);
                Dis[next] = Dis[cur] + 1;
            }
        }
    }
    if( isFound ) return Dis[cur];
    else return -1;
}

int main( ) {
    //freopen("input.txt", "r", stdin);
    int T;
    cin >> T;
    string from, to;
    Point Start, End;
    for ( int i = 0; i < T; i++ ) {
        memset(G, 0, sizeof(G));
        cin >> M >> N >> K;
        for ( int i = 1; i <= M; i++ ) {
            for ( int j = 1; j <= N; j++) {
                cin >> G[i][j];
            }
        }
        Start = Point(1, 1);
        End = Point(M, N);
        cout << BFS(Start, End) << endl;
    }
    //system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值