[图的bfs] Ideal Path Uva1599

题目描述

给定一个 n 个点 m 条边( 2 n 100000 , 1 m 20000 )的无向图。每一条边上都有一种颜色。求从 1 号节点到 n 号节点的最短路径,当路径大小相同时,取所经过节点的颜色序列字典序最小的一条路径。一对节点间可以有多天路径,同时存在自反路径。

题解

该题目中若无取字典序最小的路径的要求,则是一个简单的求最短路径问题。当然,该题中的节点个数较多。不能使用矩阵存储信息,应该使用广义表。同时,由于节点个数多,不能使用保存前驱节点的方式求最短路径。但可以反向bfs,求出每一个节点 i 到终点的最短距离 d [ i ] ,便可求出最短路径。其模板总结如下:

反向bfs求最短路径

void bfs(int n) {
    queue<int> qu;
    qu.push(n);// n 为终点
    d[n] = 1; // 将终点的距离初始化为1.不初始化为0是为了区分已访问的点和未访问的点。
    while(!qu.empty()){
        int s = qu.front();qu.pop();
        for(int i = 0; i<n; i++) if(!d[G[s][i].n]){
                d[i] = d[s]+1;
                if(s == 1) return;// 最终路径长度为d[1] - 1;
                qu.push(G[s][i].n);
        }
    }
}

这样就可以解决求最短路径问题。然而还有另一个问题:取颜色字典序最短的路径。解决方法是,再正向进行一遍bfs。这次关注的重点是节点间的“颜色”。进入队列的元素是下一层中“颜色”最小的节点,若都最小则全部入队。在实现过程中,控制入队节点的个数很重要。不然很容易超时。尽量先判断能否继续再入队,同时要防止重复入队。这里可以附加一个是否入队的判断。
综合考虑就可以解决问题。

AC代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 100001;
const int INF = 0x3f3f3f3f;

struct link{
    int n, c;
    link(int n, int c):n(n), c(c){}
};

vector<link> G[maxn];
int d[maxn];
bool inqueue[maxn];

void panswer(int n){
    queue<int> ans;
    ans.push(1);
    int out[maxn], layer;
    memset(out, INF, sizeof(out));
    while(!ans.empty()){
        int s = ans.front();ans.pop();
        if(s == n) break;
        int color = INF, len = G[s].size();
        for(int i = 0; i<len; i++)if(d[s] == d[G[s][i].n]+1) color = min(color, G[s][i].c);
        for(int i = 0; i<len; i++)if(d[s] == d[G[s][i].n]+1 && !inqueue[G[s][i].n] && color == G[s][i].c){
            ans.push(G[s][i].n); inqueue[G[s][i].n] = true;
        }
        layer = d[1] - d[s];
        out[layer] = min(out[layer], color);
    }
    printf("%d\n%d", d[1] - 1, out[0]);
    for(int i = 1; i<d[1]-1; i++) printf(" %d", out[i]);
    printf("\n");
}

void solve(int n) {
    queue<int> qu;
    qu.push(n);
    d[n] = 1;
    while(!qu.empty()){
        int s = qu.front();qu.pop();
        for(int i = 0, k = G[s].size(); i<k; i++)if(!d[G[s][i].n]){
                d[G[s][i].n] = d[s]+1;
                if(s == 1) return;
                qu.push(G[s][i].n);
            }
    }
}

void clearG(int n){ for(int i = 1; i<=n+1; i++) G[i].clear(); }

int main(){
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int n,m;
    while(scanf("%d%d", &n, &m)!=EOF){
        clearG(n);
        memset(d, 0, sizeof(d));
        int a, b, c;
        for(int i = 0; i<m; i++){
            scanf("%d%d%d", &a, &b, &c);
            if(a != b){
                G[a].push_back(link(b, c));
                G[b].push_back(link(a, c));
            }
        }
        solve(n);
        memset(inqueue, false, sizeof(inqueue));
        panswer(n);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/loyxCCS/article/details/79764220
今日推荐