欢迎来到lbxer的博客
lbxer
lbxer
晓看天色暮看云,行也思君,坐也思君

csp赛前刷题篇 图论篇 [USACO09FEB]Revamping Trails G

洛谷p2939

本题为标准的分层图板子题,借由此题再次理解一噶分层图。

分层图

啥是分层图哩  就是你建的这个图,他有好几层,神不神奇,腻不腻害!?

分层图是干啥的呢  就是用于处理对边存在额外操作。腻害吧!!

至于具体哩,图请自行搜索dalao博客 各层图之间各自按照原图联通关系连边。

注意只能出上一层到下一层,就像你修了一条道,不可能再修回去。

细节问题 有K次机会时,我们要修K+1层。开数组大小问题:m*(k+1)*4。

对于本题代码如下:

#include<cstdio>
#include<queue>
#define read(x) scanf("%d",&x)//宏定义,个人习惯
#define INF 0x3f3f3f3f//伪极大值
using namespace std;
typedef pair<int, int> pii;//个人习惯
struct Node
{
    int head, dis;
}node[210100];//数组大小注意
struct Edge
{
    int to, len, next;
}edge[4200100];//数组大小注意
int n, m, k, u, v, w, cnt, ans = INF << 1;
void addEdge(int u, int v, int w)
{
    edge[++cnt] = { v,w,node[u].head };
    node[u].head = cnt;
}
//链式前向星存图
void Dijkstra()
{
    for (int i = 1; i <= n * (k + 1); i++)
    {
        node[i].dis = INF;
    }
    //初始化时,要注意我们的点数已经不是n了,而是n*(k+1)
    node[1].dis = 0;
    priority_queue<pii, vector<pii>, greater<pii> >q;
    //小根堆
    q.push({ 0,1 });
    while (q.size())
    {
        pii tmp = q.top();
        q.pop();
        int d = tmp.first, u = tmp.second;
        if (d != node[u].dis)continue;
        for (int e = node[u].head; e; e = edge[e].next)
        {
            int v = edge[e].to;
            if (node[v].dis > edge[e].len + d)
            {
                node[v].dis = edge[e].len + d;
                q.push({ node[v].dis,v });
            }
        }
    }
}
//最短路板子不解释
int main()
{
    read(n), read(m), read(k);
    for (int i = 1; i <= m; i++)
    {
        read(u), read(v), read(w);
        for (int j = 0; j <= k; j++)
        {
            /*
            当j为0时,我们建立的是原图的边
            当j不为0时,我们建立的是分身的边
             */
            addEdge(u + j * n, v + j * n, w);
            addEdge(v + j * n, u + j * n, w);
            //上面两行是每层图之间,自身的点的连线,边权不变
            if (j == k)break;
            /*
            为什么当j==k时,要退出循环呢?
            因为如果j==k时,还建下面的边,那么就超出范围了
            可以自行感性理解一下
             */
            addEdge(u + j * n, v + (j + 1) * n, 0);
            addEdge(v + j * n, u + (j + 1) * n, 0);
            //这两行建立的是层与层之间的边,边权为0
        }
    }
    Dijkstra();
    //跑最短路
    for (int i = 0; i <= k; i++)
    {
        ans = min(ans, node[n + i * n].dis);
        //统计每一层到n距离的最小值
    }
    printf("%d\n", ans);
    //输出答案
    return 0;
}
View Code

 

posted @ 2020-10-11 20:30  雷痕小祥  阅读(190)  评论(0编辑  收藏  举报
Live2D