理想路径 Ideal Path NEERC 2010 UVa1599

【分析】

本题只是一个普通的最短路问题,可以用BFS解决。但是“记录父结点”的方法已经不适用了,因为这样打印出来的路径并不能保证字典序最小。

事实上。无须记录父结点也能得到最短路,方法是从终点开始“倒着”BFS,得到每个结点i到终点的最短距离d[i],然后直接从起点开始走,但是每次到达一个新结点时要保证d值恰好减少1(如有个选择则可以随便走),直到到达终点。

直接从起点开始按照上述规则走,如果有多种走法,选颜色字典序最小的走;如果有多条边的颜色字典序都是最小,则记录所有这些边的终点,走下一步时要考虑从所有这些点出发的边。这实际上是又做了一次BFS,因此时间复杂度仍为O(m)。

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
const ll inf = 1e9 + 5;
const int maxn = 100000 + 5;
int n, m, d[maxn], vis[maxn], nextNode[maxn], tempNode[maxn];
struct edge
{
    int v, w;
    edge(int b, int c) : v(b), w(c) {}
};
vector<edge> e[maxn];
int main(void)
{
    while (~scanf("%d %d", &n, &m))
    {
        memset(vis, 0, sizeof(vis));
        memset(d, inf, sizeof(d));
        for (int i = 1; i <= n; i++)
            e[i].clear();
        while (m--)
        {
            int a, b;
            ll c;
            scanf("%d %d %lld", &a, &b, &c);
            e[a].push_back(edge(b, c));
            e[b].push_back(edge(a, c));
        }
        queue<int> Q;
        Q.push(n);
        vis[n] = 1;
        d[n] = 0;
        while (!Q.empty())
        {
            int u = Q.front();
            Q.pop();
            for (int i = 0; i < e[u].size(); i++)
            {
                int v = e[u][i].v;
                if (vis[v])
                    continue;
                vis[v] = 1;
                d[v] = d[u] + 1;
                Q.push(v);
            }
        }
        memset(vis, 0, sizeof(vis));
        vis[1] = 1;
        int size = 0;
        nextNode[size++] = 1;
        printf("%d\n", d[1]);
        for (int step = 0; step < d[1]; step++)
        {
            int cnt = 0;
            ll minColor = inf;
            for (int i = 0; i < size; i++)
            {
                int u = nextNode[i]; //所有的u和n的距离都相同
                for (int j = 0; j < e[u].size(); j++)
                {
                    int v = e[u][j].v;
                    if (d[v] != d[u] - 1)
                        continue; //保证再走一步会缩小距离
                    if (e[u][j].w <= minColor)
                    { //找最小的颜色
                        if (e[u][j].w < minColor)
                        {
                            cnt = 0;
                            minColor = e[u][j].w;
                        }
                        tempNode[cnt++] = v;
                    }
                }
            }
            printf("%lld%c", minColor, (step == d[1] - 1) ? '\n' : ' ');
            int cnt2 = 0;
            for (int i = 0; i < cnt; i++)
            {
                if (vis[tempNode[i]])
                    continue;
                vis[tempNode[i]] = 1;
                nextNode[cnt2++] = tempNode[i];
            }
            size = cnt2;
        }
    }
    system("pause");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值