[USACO2008MAR] 牛跑步 Cow Jogging G

题目描述

贝西终于尝到了懒惰的后果,决定每周从谷仓到池塘慢跑几次来健身。当然,她不想跑得太累,所以她只打算从谷仓慢跑下山到池塘,然后悠闲地散步回谷仓。

同时,贝西不想跑得太远,所以她只想沿着通向池塘的最短路径跑步。一共有 �M 条道路,其中每一条都连接了两个牧场。这些牧场从 11 到 �N 编号,如果 �>�X>Y,则说明牧场 �X 的地势高于牧场 �Y,即下坡的道路是从 �X 通向 �Y 的,�N 为贝西所在的牛棚(最高点),11 为池塘(最低点)。

然而,一周之后,贝西开始对单调的路线感到厌烦,她希望可以跑不同的路线。比如说,她希望能有 �K 种不同的路线。同时,为了避免跑得太累,她希望这 �K 条路线是从牛棚到池塘的路线中最短的 �K 条。如果两条路线包含的道路组成的序列不同,则这两条路线被认为是不同的。

请帮助贝西算算她的训练强度,即将牧场网络里最短的 �K 条路径的长度分别算出来。你将会被提供一份牧场间路线的列表,每条道路用 (��,��,��)(Xi​,Yi​,Di​) 表示,意为从 ��Xi​ 到 ��Yi​ 有一条长度为 ��Di​ 的下坡道路。

输入格式

第一行三个用空格分开的整数 �,�,�N,M,K,其中 。

第二行到第 �+1M+1 行每行有三个用空格分开的整数 ��,��,��Xi​,Yi​,Di​,描述一条下坡的道路。

输出格式

共 �K 行,在第 �i 行输出第 �i 短的路线长度,如果不存在则输出 −1−1。如果出现多种有相同长度的路线,务必将其全部输出。

样例

输入数据#1

5 8 7 
5 4 1 
5 3 1 
5 2 1 
5 1 1 
4 3 4 
3 1 1 
3 2 1 
2 1 1

输出数据#1

1 
2 
2 
3 
6 
7 
-1

解释#1

这些路线分别为 (5-1)、(5-3-1)、(5-2-1)、(5-3-2-1)、(5-4-3-1) 和 (5-4-3-2-1)。

数据范围

  • 对于全部的测试点,保证 1≤�≤1,0001≤N≤1,000,1≤�≤1×1041≤M≤1×104,1≤�≤1001≤K≤100,1≤��<��≤�1≤Yi​<Xi​≤N,1≤��≤1×1061≤Di​≤1×106,
  • https://www.topscoding.com/p/1081icon-default.png?t=N6B9https://www.topscoding.com/p/1081

    AC代码:

  • #include<bits/stdc++.h>
    using namespace std;
    struct edge {
        int v, w, next;
    } e[100010], e1[100010];
    int head[1010], head1[1010], cnt;
     
    int n, m, k;
    int dis[1010];
    bool vis[1010];
     
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
        return x * f;
    }
     
    void insert(int u, int v, int w) {
        e[++cnt].v = v, e[cnt].w = w, e[cnt].next = head[u], head[u] = cnt;
        e1[cnt].v = u, e1[cnt].w = w, e1[cnt].next = head1[u], head1[u] = cnt;
    	//反向建图 
    }
     
    void spfa() {
        memset(dis, 1e9, sizeof dis);
        queue<int> q;
        dis[n] = 0;
        vis[n] = 1;
        q.push(n);
        int u;
        while (!q.empty()) {
    	u = q.front();
    	q.pop();
    	vis[u] = false;
    	for (int i = head1[u]; i; i = e1[i].next) {
    	    int v = e1[i].v, w = e1[i].w;
    	    if (dis[v] > dis[u] + w) {
    		dis[v] = dis[u] + w;
    		if (!vis[v]) {
    		    vis[v] = true;
    		    q.push(v);
    		}
    	    }
    	}
        }
    }
     
    struct node {
        int d, id;
        node () {}
        node (int dd, int di) {
    	d = dd;
    	id = di;
        }
        bool operator < (const node & x) const {
    	return x.d < d;
        }
    };
     
    int ans[110], kk;
    priority_queue<node> q;
    void A_star() {
        q.push(node(dis[n], n));
        while (!q.empty()) {
    	int d = q.top().d, num = q.top().id;
    	q.pop();
    	if (num == 1) {
    	    ans[++kk] = d;
    	    if (kk == k) return;
    	}
    	for (int i = head[num]; i; i = e[i].next) {
    	    q.push(node(d - dis[num] + e[i].w + dis[e[i].v], e[i].v));
    	}
        }
    }
     
    int main() {
        n = read(), m = read(), k = read();
        for (int i = 1; i <= m; i++) {
    	int u = read(), v = read(), w = read();
    	insert(u, v, w);
        }
        spfa();
        A_star();
        for (int i = 1; i <= k; i++) {
    	if (ans[i]) printf("%d\n", ans[i]);
    	else puts("-1");
        }
        return 0;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值