• 【spfa训练】HDU4725 (层级建图)


    HDU4725

    题目大意:一些节点分布在不同的层上,已知相邻的层可以往来距离为c,在给你一些已知的边,问你点1-n的最短路

    分析:越往后做,越觉得最短路的考点已经不是spfa算法还是dijkscar算法了,而是图形的创建,你脑海里既要有他给你描绘出的问题场景图,也要有适应算法而建造的图模型,其实这个题有很多的建图方式,看你怎么想了,只能说我的模型化思想还没有完全好,这个图在我脑子里已经TLE了,看了看别人的题目大意又重整旗鼓模拟了一下~~

    就是你把一个层就看做一个点,一开始的输入会告诉你每一个点具体在第几层,你可以标记一下,哪些层出现过(TLE点1:你当然可以不标记,然后给每一个相邻的层建边,但是spfa就会麻烦了,tle,因为很可能你会在没有点的层上乱逛)

    for(int i = 1;i <= n;i++)
            {
                scanf("%d",&flor[i]);//i点在l层
                vis[flor[i]] = 1;
            }
            for(int i = 1;i < n;i++)
            {
                if(vis[i] && vis[i + 1])
                {
                    add(i + n,i + n + 1,c);
                    add(i + n + 1,i + n,c);
                }
            }
    

     层层间的路建好了,就剩下点和层的了,(TLE点2:一般都会想的是,把点和它所在的层一一连接起来就好了也就是i 和 n + flor[i]),其实这是一条比较费的路,只会徒增加时间,要知道spfa的队列限制了它一步一步更新最短路,所以你的结点越多,也就会越慢,所以直接跨越一个结点,连接i和i层所在的上下层

    剩下的就真的是默写spfa了

    #include <iostream>
    #include <queue>
    #include <cstdio>
    #include <string.h>
    #include <vector>
    #define inf 0x3f3f3f3f
    using namespace std;
    const int maxn = 3e5 + 3e2;
    
    struct node
    {
        int to,cost,pre;
    //    node(int t,int c,int p):to(t),cost(c),pre(p){}
    }edge[maxn * 10];
    //vector<node> edge[maxn];
    int n;
    int d[maxn];
    int vis[maxn];
    int id[maxn];
    int cnt;int flor[maxn];
    queue<int>q;
    void init()
    {
    //    memset(vis,0,sizeof(vis));
    //    memset(id,-1,sizeof(id));
        for(int i = 1;i <= 3*n;i++)
        {
    //      edge[i].clear();
            d[i] = inf;
            vis[i] = 0;
            id[i] = -1;
        }
        memset(flor,0,sizeof(flor));
        cnt = 0;
        while(!q.empty())q.pop();
    }
    void add(int from,int to,int cost)
    {
    //    edge[from].push_back(node(to,cost));
        edge[cnt].to = to;
        edge[cnt].cost = cost;
        edge[cnt].pre = id[from];
        id[from] = cnt++;
    }
    void spfa(int s)
    {
        memset(vis,0,sizeof(vis));
        d[s] = 0;
        vis[s] = 1;
        q.push(s);
        while(q.size())
        {
            int now = q.front();q.pop();vis[now] = 0;
    //        for(int i = 0;i < edge[now].size();i++)
            for(int i = id[now];~i;i = edge[i].pre)
            {
    //            cout<<i<<endl;
    //            int to = edge[now][i].to;
    //            int cost = edge[now][i].cost;
                int to = edge[i].to;
                int cost = edge[i].cost;
                if(d[to] > d[now] + cost)
                {
                    d[to] = d[now] + cost;
                    if(!vis[to])
                    {
                        vis[to] = 1;
                        q.push(to);
                    }
                }
            }
        }
    }
    
    int main()
    {
        int t,m,c,a,b,x;
        scanf("%d",&t);
        int cas = 1;
        while(t--)
        {
            scanf("%d%d%d",&n,&m,&c);
            init();
            for(int i = 1;i <= n;i++)
            {
                scanf("%d",&flor[i]);//i点在l层
                vis[flor[i]] = 1;
            }
            for(int i = 1;i < n;i++)
            {
                if(vis[i] && vis[i + 1])
                {
                    add(i + n,i + n + 1,c);
                    add(i + n + 1,i + n,c);
                }
            }
            for(int i = 1;i <= n;i++)
            {
                add(n + flor[i],i,0);
                if(flor[i] > 1)
                    add(i,n + flor[i] - 1,c);
                if(flor[i] < n)
                    add(i,n + flor[i] + 1,c);
            }
            while(m--)
            {
                scanf("%d%d%d",&a,&b,&x);
                add(a,b,x);
                add(b,a,x);
            }
            spfa(1);
            if(d[n] == inf)d[n] = -1;
            printf("Case #%d: %d
    ",cas++,d[n]);
        }
        return 0;
    }
    

     WA了11次!思路很重要~!

  • 相关阅读:
    菱形继承问题
    类的组合
    类的派生
    EasyUI的columns中列标题居中
    C#的一般处理程序中Cookie的写入、读取、清除
    JS中设置input的type="radio"默认选中
    SQL Server 分页语句查询
    CSS中设置字体样式
    C#清空StringBuilder的三种方法
    EasyUI在子tab基础上再打开新的tab标签页
  • 原文地址:https://www.cnblogs.com/DF-yimeng/p/8569668.html
Copyright © 2020-2023  润新知