C++ 電路佈線/最短路徑問題

問題描述

用二維數組表示地圖,若值爲 1 則表示有障礙物,若值爲 0 則表示能夠通行。ios

輸入: m*n 的二維數組,佈線起點座標,佈線終點座標。數組

輸出: 最短佈線距離以及對應的佈線路徑。this

 

問題分析

從起點開始佈線,將起點標記爲 0 ,把四周可佈線的位置標記爲 起點標記值 + 1 ,同時將這些點插進隊列 Q (插到隊尾)。spa

從 Q 中取出一個點(隊首元素)重複佈線動做,將可佈線位置標記爲 取出點標記值 + 1 ,並插進 Q 。不斷重複上一個動做,直到找到終點,此時終點的標記值即最短佈線距離。code

爲何終點的標記值會等於最短佈線距離呢?blog

事實上對於每一點這個結論都是成立的(某點的標記值=該點到起點的最短距離)。隊列

(方塊表示起點,橢圓表示終點)it

在佈線的過程當中,始終遵循的規則是:標記值越小的越先佈線。(越先入隊的越先佈線)io

咱們假設對於標記值爲 n 的點該結論成立,咱們只須要證實從標記值爲 n 的點出發,找到的標記值爲 n+1 的點確實最短就能夠了。class

咱們考察標記值 n 周圍的可佈線點,能夠分爲兩類:已佈線點和未佈線點。

對於未佈線的點:由佈線規則可知,全部標記值 < n 點都已經佈線完畢,點未被佈線的惟一緣由是任何一個標記值 < n 的點都沒法與它相鄰(到不了或者須要付出更大的代價才能到),因此該點只能經過點 n 或者相鄰的標記值一樣爲 n 的點與起點聯通,從而取得最小值,故對標記值爲 n+1 的點結論一樣成立。

所以該結論對於任意標記值的點都成立。

 

C++ 代碼

#include <stdio.h>
#include <cstdlib>
#include <iostream>
#include <queue>
  
using namespace std;
#define MAX 6

struct Point {
    int x;
    int y;
    int len;
    Point* pre;

    Point(): len(0), pre(0) {}
    Point(int x, int y): x(x), y(y), len(0), pre(0) {}
    void setPoint(int x, int y) {
        this->x = x;
        this->y = y;
    }
};


queue<Point> mark;
void test(Point (*p)[MAX]);

bool work(Point& q, Point& e, int (*map)[MAX], Point (*p)[MAX]) {
    int x, y;
    // up 
    if ((x=q.x-1) >= 0 && map[x][y=q.y] != 1 && p[x][y].len == 0) {
        p[x][y].len = q.len + 1;
        p[x][y].pre = &q;
        if (x == e.x && y == e.y) {
            return true;
        } else {
            mark.push(p[x][y]);
        }
    }
    // down 
    if ((x=q.x+1) < MAX && map[x][y=q.y] != 1 && p[x][y].len == 0) {
        p[x][y].len = q.len + 1;
        p[x][y].pre = &q;
        if (x == e.x && y == e.y) {
            return true;
        } else {
            mark.push(p[x][y]);
        }
    }
    // left 
    if ((y=q.y-1) >= 0 && map[x=q.x][y] != 1 && p[x][y].len == 0) {
        p[x][y].len = q.len + 1;
        p[x][y].pre = &q;
        if (x == e.x && y == e.y) {
            return true;
        } else {
            mark.push(p[x][y]);
        }
    }
    // right 
    if ((y=q.y+1) < MAX && map[x=q.x][y] != 1 && p[x][y].len == 0) {
        p[x][y].len = q.len + 1;
        p[x][y].pre = &q;
        if (x == e.x && y == e.y) {
            return true;
        } else {
            mark.push(p[x][y]);
        }
    }
    return false;
}

void f(int (*map)[MAX], Point& s, Point& e, bool& k, Point (*p)[MAX]) {
    mark.push(s);
    int flag = false;
    while (mark.size() != 0 && !flag) { // 終止條件:找遍全部點都沒找到終點&找到終點
        flag = work(mark.front(), e, map, p);
        mark.pop();
        test(p); // 輸出佈線狀況
    }
    k = flag;
}

void test(Point (*p)[MAX]) { // 輸出佈線狀況
    for (int i = 0; i != MAX; ++i) {
        for (int j = 0; j != MAX; ++j) {
            printf("%d ", p[i][j].len);
        }
        cout << endl;
    }    
    cout << endl;
}

void printPath(Point& end) {
    if (end.pre == 0) {
        printf("[%d][%d]\n", end.x, end.y);
        return;
    } else {
        printPath(*(end.pre));
        printf("[%d][%d]\n", end.x, end.y);
    }
}

int main()
{
    int map[MAX][MAX] = { 0, 0, 0, 0, 0, 1,
                          0, 0, 0, 0, 1, 0,
                          0, 0, 0, 0, 0, 1,
                          0, 0, 0, 1, 0, 1,
                          0, 1, 0, 0, 0, 0,
                          1, 1, 0, 1, 1, 1 };

    Point s(1, 1);
    Point e(4, 4);
    
    bool k = false;
    Point p[MAX][MAX];
    p[s.x][s.y].len = 1;
    for (int i = 0; i != MAX; ++i) {
        for (int j = 0; j != MAX; ++j) {
            p[i][j].setPoint(i, j);
        }
    } // 初始化
    
    f(map, s, e, k, p);
    if (k) {
        printf("MIN=%d\n", p[e.x][e.y].len);
        printPath(p[e.x][e.y]);
    } else {
        printf("ERROR\n"); // 起點與終點不連通
    }
    
    return 0;
}

 

附件:迷宮問題

上面那道題用隊列,這道用棧。

#include <stdio.h>
#define MAX 7

struct Point {
    int x;
    int y;
    bool mark;
    Point(): x(0), y(0), mark(false) {}
    Point(int x, int y): x(x), y(y) {}
    void setPosition(int x, int y) {
        this->x = x;
        this->y = y;
    }
};

Point p[MAX][MAX];
bool seekPath(int (*map)[MAX], Point& s, Point& e) {
    p[s.x][s.y].mark = true;
    if (s.x == e.x && s.y == e.y) {
        printf("MAP[%d][%d]\n", e.x, e.y);
        return true;
    }

    //printf("seekPath:1\n");
    if (s.x+1 < MAX && map[s.x+1][s.y] != 1 && !p[s.x+1][s.y].mark && seekPath(map, p[s.x+1][s.y], e)) {
            printf("MAP[%d][%d]\n", s.x, s.y);
            return true;
    }
    //printf("seekPath:2\n");
    if (s.x-1 >= 0 && map[s.x-1][s.y] != 1 && !p[s.x-1][s.y].mark && seekPath(map, p[s.x-1][s.y], e)) {
            printf("MAP[%d][%d]\n", s.x, s.y);
            return true;
    }
    //printf("seekPath:3\n");
    if (s.y+1 < MAX && map[s.x][s.y+1] != 1 && !p[s.x][s.y+1].mark && seekPath(map, p[s.x][s.y+1], e)) {
            printf("MAP[%d][%d]\n", s.x, s.y);
            return true;
    }
    //printf("seekPath:4\n");
    if (s.y-1 >= 0 && map[s.x][s.y-1] != 1 && !p[s.x][s.y-1].mark && seekPath(map, p[s.x][s.y-1], e)) {
            printf("MAP[%d][%d]\n", s.x, s.y);
            return true;
    }
    //printf("seekPath:5\n");
    if (s.x+1 < MAX && s.y+1 < MAX && map[s.x+1][s.y+1] != 1 && !p[s.x+1][s.y+1].mark && seekPath(map, p[s.x+1][s.y+1], e)) {
            printf("MAP[%d][%d]\n", s.x, s.y);
            return true;
    }
    //printf("seekPath:6\n");
    if (s.x+1 < MAX && s.y-1 >= 0 && map[s.x+1][s.y-1] != 1 && !p[s.x+1][s.y-1].mark && seekPath(map, p[s.x+1][s.y-1], e)) {
            printf("MAP[%d][%d]\n", s.x, s.y);
            return true;
    }
    //printf("seekPath:7\n");
    if (s.x-1 >= 0 && s.y+1 < MAX && map[s.x-1][s.y+1] != 1 && !p[s.x-1][s.y+1].mark && seekPath(map, p[s.x-1][s.y+1], e)) {
            printf("MAP[%d][%d]\n", s.x, s.y);
            return true;
    }
    //printf("seekPath:8\n");
    if (s.x-1 >= 0 && s.y-1 >= 0 && map[s.x-1][s.y-1] != 1 && !p[s.x-1][s.y-1].mark && seekPath(map, p[s.x-1][s.y-1], e)) {
            printf("MAP[%d][%d]\n", s.x, s.y);
            return true;
    }
    return false;
}

void f(int (*map)[MAX], Point& s, Point& e) {
    // chushihua
    for (int i = 0; i != MAX; ++i) {
        for (int j = 0; j != MAX; ++j) {
            p[i][j].setPosition(i, j);
        }
    }

    // work
    if (!seekPath(map, s, e)) {
        printf("ERROR!\n");
    }
    //printf("f:runnable\n");
}

int main()
{
    int map[MAX][MAX] = { 0, 1,    1, 0, 0, 0,    0,
                          0, 0, 1, 1, 0, 0, 0,
                          1, 0, 0, 0, 1, 0, 0,
                          0, 0, 0, 1, 1, 0, 1,
                          1, 0, 0, 0, 1, 0, 1,
                          1, 1, 1, 0, 0, 0, 0,
                          1, 1, 1, 1, 1, 0, 0 };
    Point s(0, 0);
    Point e(2, 6);    
    f(map, s, e);
    //printf("main:runnable\n");
    return 0;
}

留着備用。

相關文章
相關標籤/搜索