[ACdream]小Y上学记——要迟到了![最短路][spfa]

D - 小Y上学记——要迟到了!

Time Limit:  2000/1000MS (Java/Others)     Memory Limit:  128000/64000KB (Java/Others)
Submit  Status

Problem Description

“你是我心中最美的云彩....",这不是大妈的广场舞,而是小Y的闹钟,然而小Y由于昨晚玩得太疯,导致今天居然没被这铃声闹醒!

当小Y睡眼惺忪地醒来后,发现距离第一节上课还有不到5分钟了!

小Y心想,跑过去教室肯定来不及了,只好发动一下超能力。

小Y的超能力是可以瞬间通过一条路,也就是说从一头瞬间移动到另一头,然而由于某种原因,小Y最多只能发动K次,不然就会被大家发现,就会被上交给国家。

那么小Y想问你最快要多长时间到达教室?

Input

多组数据,每组数据首先是三个整数N,M,K,表示校园道路的节点数,校园道路数,还有小Y能发动超能力的最大次数。

(2<=N<=1000,N-1<=M<=10000,0<=K<=10)

接下来是M行,每行是三个数字u,v,w,表示在节点u和节点v中有一条需要小Y跑w分钟的路,道路都是没有方向限制的。

(1<=u,v<=N,0<w<=1000)

可能有自环以及重边

其中小Y宿舍在1号节点,教室在n号节点。

保证从宿舍到教室至少存在一条路。

Output

对于每组数据,输出一个整数,表示小Y在超能力的帮助下最少要多少时间到达教室。

Sample Input

4 4 0
1 2 2
2 4 3
1 3 1
3 4 4
4 4 1
1 2 2
2 4 3
1 3 1
3 4 4

Sample Output

5
1

Hint

对于第一组数据,由于小Y不能使用超能力,无论是1-2-4还是1-3-4,都需要花费小Y5分钟的时间

对于第二组数据,由于小Y可以用一次超能力,因此可以选择1-3-4这条道路,其中3-4这条道路使用超能力通过。只需要1分钟。


解题思路:

这道题和平常的最短路,唯一区别就是这一次可以选择性的忽略几条路。使用spfa的话,一般的状态是以d[u]更新它所能到达的边,这次多了一个跳过选项,所以可以更新的状态多了一种d[i][u] = min(d[i][u], d[i - 1][v]),使用了i次能力能到达的一个状态,当i<k时,就可以进行转移。所以最终这题需要的状态就是一个二维的状态。

个人感受:

能想到二维,感觉同学们真机智,受教了。

具体代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int INF = 0x7f7f7f7f, MAXN = 1111;
struct N{
    int to, next, val;
}edge[MAXN*MAXN];
int n, m, k, d[20][MAXN], cnt, head[MAXN];
bool in[20][MAXN];

void add_edge(int u, int v, int w)
{
    edge[cnt].to = v;
    edge[cnt].val = w;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

void init()
{
    cnt = 0;
    memset(head, -1, sizeof head);
    for (int i = 0; i < m; ++i)
    {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        if (u == v) continue;
        add_edge(u, v, w);
        add_edge(v, u, w);
    }
}

void spfa(int s)
{
    memset(d, 0x7f, sizeof d);
    memset(in, 0, sizeof in);
    d[0][s] = 0;
    queue<pii> q;
    q.push(pii(0, s));
    in[0][s] = 1;
    while (q.size())
    {
        pii now = q.front(); q.pop();
        int cei = now.first, e = now.second; //cei:使用了几次能力。当前层数
        in[cei][e] = 0;
        for (int i = head[e]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if (d[cei][v] > d[cei][e] + edge[i].val) //不使用超能力
            {
                d[cei][v] = d[cei][e] + edge[i].val;
                if (!in[cei][v])
                {
                    in[cei][v] = 1;
                    q.push(pii(cei, v));
                }
            }
            if (cei < k && d[cei + 1][v] > d[cei][e]) //使用
            {
                d[cei + 1][v] = d[cei][e];
                if (!in[cei + 1][v])
                {
                    in[cei + 1][v] = 1;
                    q.push(pii(cei + 1, v));
                }
            }
        }
    }
}

int main()
{
    while(~scanf("%d%d%d", &n, &m, &k))
    {
        init();
        spfa(1);
        printf("%d\n", d[k][n]);
    }
    return 0;
}


你可能感兴趣的:(图论,SPFA,ACdream)