UVA 1599 理想路径

这道题思路很清楚,先反向bfs搜索点n到每个点的最短距离,然后再从点1正向bfs搜索,每次搜索距离减1的点,并将路径上颜色最小的点入队,如果有多个相同的则将这多个点入队。
对于队列中的任意一个点v,d[1]-d[v]一定是大于等于0的,所以可以用cost[d[1]-d[v]]来记录到点1为d[1]-d[v]距离的最小颜色值。一开始写完交上去TLE,还以为是每次调用n次vector的clear太慢,后来看网上的代码才发现是节点重复入队的问题,所以这里需要记录一个节点是否已经在队列中了,避免重复入队,时间复杂度才为O(m),不然就是O(n^2)了。

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
using namespace std;

const int maxn = 100005;
const int maxm = 200005;

struct Edge{
    int to;
    int cost;
    Edge(int t, int c){
        to = t;
        cost = c;
    }
    Edge(){

    }
};
vector<Edge> g[maxn];
int d[maxn];
int n, m;
int cost[maxn];
int vis[maxn];
bool inqueue[maxn];

void bfs(){
    queue<int> q;
    q.push(n);
    memset(d, -1, sizeof(d));
    d[n] = 0;
    while (!q.empty()){
        int p = q.front();
        q.pop();
        for (int i = 0; i < g[p].size(); i++){
            int to = g[p][i].to;
            if (d[to] < 0){
                d[to] = d[p] + 1;
                if (to == 1)
                    return;
                q.push(to);
            }
        }
    }
}

void printans(){
    cout << d[1] << endl;
    cout << cost[1];
    for (int i = 2; i <= d[1]; i++)
        cout <<" "<< cost[i];
    cout << endl;
}

void bfs2(){

    memset(cost, 0x3f, sizeof(cost));
    memset(vis, 0, sizeof(vis));
    memset(inqueue, 0, sizeof(inqueue));
    queue<int> q;
    q.push(1);
    inqueue[1] = true;
    while (!q.empty()){
        int v = q.front();
        q.pop();
        vis[v] = true;
        if (v == n)
            break;
        for (int i = 0; i < g[v].size(); i++){
            int t = g[v][i].to;
            if (d[t] == d[v] - 1 && !vis[t] && g[v][i].cost < cost[d[1] - d[t]])
                cost[d[1] - d[t]] = g[v][i].cost;
        }

        for (int i = 0; i < g[v].size(); i++){
            int t = g[v][i].to;
            if (d[t] == d[v] - 1 && !inqueue[t] && !vis[t] && g[v][i].cost == cost[d[1] - d[t]]){
                inqueue[t] = true;//用来防止节点重复入队
                q.push(t);
            }
        }
    }

    printans();
}


int main(){
    while (cin >> n >> m){
        for (int i = 1; i <= n; i++)
            g[i].clear();
        for (int i = 0; i < m; i++){
            int s, e, c;
            scanf("%d%d%d", &s, &e, &c);
            if (s != e){
                g[s].push_back(Edge(e, c));
                g[e].push_back(Edge(s, c));
            }
        }
        bfs();
        bfs2();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值