HDU 4725 The Shortest Path in Nya Graph(好题)

来源:互联网 发布:学党规 知敬畏守规矩 编辑:程序博客网 时间:2024/06/01 07:50

题目链接:kuangbin带你飞 专题四 最短路练习 P - The Shortest Path in Nya Graph

题意

共n个点,n层(每个点单独一层),相邻的两层之间权值为w
还有m条额外的边,权值为v,求1到n的最短路

思路

本题可谓好题。时间空间都卡的相当死,硬把我从timeout逼到memorylimit。在求最短路上,本题没有什么难度,dijkstra+heap或者spfa邻接表都行。但是在建图上,我一开始是将每个点所在的层数记录下来,然后两重循环进行判断是否相邻来赋权。丝毫没有意识到n的范围10**5,必然超时。
久思无果后参看大牛博客,才发现一种空间换时间的法子
给每个点两个辅助点,一个做出度,一个做入度,赋其与辅助点边权为0(因为原本就是一个点),而且这两个辅助点完全可以按照层数来排列,这样就可以把建图优化到O(n)
如果还超时,可以用双端队列来对spfa进行优化

代码

#include<iostream>#include<cstring>#include<cmath>#include<cstdio>#include<algorithm>#include<stack>#include<queue>using namespace std;const int N = 100009;const int MAX = 0x3f3f3f3f;int d[3*N];bool vis[3*N];int h[3*N];struct Edge{    int u, v, w, next;}e[5*N];int num = 0;int spfa(int n){    memset(vis, 0, sizeof(vis));    memset(d, 0x3f3f3f3f, sizeof(d));    d[1] = 0;    vis[1] = 1;    deque<int> q;    q.push_back(1);    while(!q.empty())    {        int x = q.front();        q.pop_front();        vis[x] = 0;        for(int i=h[x]; i!=-1; i=e[i].next)        {            if(d[e[i].v] > d[x] + e[i].w)            {                d[e[i].v] = d[x] + e[i].w;                if(!vis[e[i].v])                {                    if(d[e[i].v] < d[q.front()] && !q.empty())                        q.push_front(e[i].v);                    else                        q.push_back(e[i].v);                    vis[e[i].v] = 1;                }            }        }    }    if(d[n] == MAX)        return -1;    return d[n];}void addedge(int u, int v, int w){    e[num].u = u;    e[num].v = v;    e[num].w = w;    e[num].next = h[u];    h[u] = num++;}int main(){    int T;    scanf("%d", &T);    for(int tt=1; tt<=T; tt++)    {        int n,m,w;        num = 0;        memset(h, -1, sizeof(h));        scanf("%d%d%d", &n, &m, &w);        for(int i=1; i<=n; i++)        {            int t;            scanf("%d", &t);            addedge(i, n+t*2-1, 0);            addedge(n+t*2, i, 0);        }        for(int i=1; i<n; i++)        {            addedge(n+2*i+1, n+2*i, w);            addedge(n+2*i-1, n+2*i+2, w);        }        for(int i=1; i<=m; i++)        {            int a, b, c;            scanf("%d%d%d", &a, &b, &c);            addedge(a, b, c);            addedge(b, a, c);        }        printf("Case #%d: %d\n", tt, spfa(n));    }    return 0;}
0 0