HDU6705 CCPC网络赛 path

题目链接
题解:
直接优先队列 bfs 将每条出边都压入队列会因为边数太多而 MLE,所以考虑一下减少放入队列的边。会发现每次只用压入两条边进队列。
首先将每个点边权最小的出边加入优先队列,然后 bfs 时每 pop 出一条边就将出点是这条边的点的下一条出边压入队列,同时将连接这条边的最短的边也压入队列进行 bfs 即可。
具体的优先队列中维护四个值:这条边作为出边的编号、这条边作为出边的点的编号、这条边到达的点的编号、目前为止的距离。
代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<ll, int>
#define debug(x) cout << (#x) << ": " << (x) << " "
#define fastio ios::sync_with_stdio(false), cin.tie(0)
const int mod = 1e9 + 7;
const int M = 15 + 10;
const int N = 50000 + 10;

int t, n, m, q;
struct node {
    int id, now, to, dis;
    bool operator < (const node &cmp) const {
        return dis > cmp.dis;
    }
} ;
priority_queue<node> que;
vector<P> G[N];
int mxk, k[N], ans[N];

void bfs()
{
    int cnt = 0;
    while(que.size()) {
        node tp = que.top(), temp;
        que.pop();
        ans[++cnt] = tp.dis;
        if(cnt >= mxk) break;
        if(tp.id + 1 < G[tp.now].size()) {
            temp.dis = tp.dis - G[tp.now][tp.id].first + G[tp.now][tp.id + 1].first;
            temp.id = tp.id + 1;
            temp.now = tp.now;
            temp.to = G[tp.now][tp.id + 1].second;
            que.push(temp);
        }
        if(G[tp.to].size()) {
            temp.dis = tp.dis + G[tp.to][0].first;
            temp.id = 0;
            temp.now = tp.to;
            temp.to = G[tp.to][0].second;
            que.push(temp);
        }
    }
}

signed main()
{
    scanf("%d", &t);
    while(t --) {
        while(que.size()) que.pop();
        scanf("%d %d %d", &n, &m, &q);
        for(int i = 1; i <= n; i ++) G[i].clear();
        for(int i = 1; i <= m; i ++) {
            int u, v, w;
            scanf("%d %d %d", &u, &v, &w);
            G[u].push_back({w, v});
        }


        for(int i = 1; i <= n; i ++) {
            if(G[i].size()) {
                sort(G[i].begin(), G[i].end());
                que.push({0, i, G[i][0].second, G[i][0].first});
            }
        }

        mxk = 0;
        for(int i = 1; i <= q; i ++) {
            scanf("%d", &k[i]);
            mxk = max(mxk, k[i]);
        }

        bfs();

        for(int i = 1; i <= q; i ++) {
            printf("%d\n", ans[k[i]]);
        }
    }
    return 0;
}

/*

  Rejoicing in hope, patient in tribulation.

*/

/*

             ,----------------,              ,---------,
        ,-----------------------,          ,"        ,"|
      ,"                      ,"|        ,"        ,"  |
     +-----------------------+  |      ,"        ,"    |
     |  .-----------------.  |  |     +---------+      |
     |  |                 |  |  |     | -==----`|      |
     |  |                 |  |  |     |         |      |
     |  |    Accepted _   |  |  |/----|`---=    |      |
     |  |                 |  |  |   ,/|==== OOO |      ;
     |  |                 |  |  |  // |(((( [33]|    ,"
     |  `-----------------`  |," .//| |((((     |  ,"
     +-----------------------+  //  | |         |,"
        /_)______________(_/  //`   | +---------+
   ___________________________/___  `,
  /  oooooooooooooooo  .o.  oooo /,   \,"-----------
 / ==ooooooooooooooo==.o.  ooo= //   ,`\--{)B     ,"
/_==__==========__==_ooo__ooo=_/`   /___________,"

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值