hdu 4725 The Shortest Path in Nya Graph (最短路+建图)

The Shortest Path in Nya Graph

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 11694    Accepted Submission(s): 2537


Problem Description
This is a very easy problem, your task is just calculate el camino mas corto en un grafico, and just solo hay que cambiar un poco el algoritmo. If you do not understand a word of this paragraph, just move on.
The Nya graph is an undirected graph with "layers". Each node in the graph belongs to a layer, there are N nodes in total.
You can move from any node in layer x to any node in layer x + 1, with cost C, since the roads are bi-directional, moving from layer x + 1 to layer x is also allowed with the same cost.
Besides, there are M extra edges, each connecting a pair of node u and v, with cost w.
Help us calculate the shortest path from node 1 to node N.
 
Input
The first line has a number T (T <= 20) , indicating the number of test cases.
For each test case, first line has three numbers N, M (0 <= N, M <= 105) and C(1 <= C <= 103), which is the number of nodes, the number of extra edges and cost of moving between adjacent layers.
The second line has N numbers li (1 <= li <= N), which is the layer of ith node belong to.
Then come N lines each with 3 numbers, u, v (1 <= u, v < =N, u <> v) and w (1 <= w <= 104), which means there is an extra edge, connecting a pair of node u and v, with cost w.
 
Output
For test case X, output "Case #X: " first, then output the minimum cost moving from node 1 to node N.
If there are no solutions, output -1.
 
Sample Input
2 3 3 3 1 3 2 1 2 1 2 3 1 1 3 3 3 3 3 1 3 2 1 2 2 2 3 2 1 3 4
 
Sample Output
Case #1: 2 Case #2: 3
题目大意:
给你一堆点。首先,这些点之间有一些双向边;然后,这些点都有自己的一个分层。相邻层的点互相之间可以花费代价c互相到达。求单源最短路。
 
最短路的建图问题。
给每层安排一个入点一个出点。入点到该层每点安排一条权值为0的单向边;出点到该层每点有一条反向的权值为0的单向边;出点有一条到相邻层入点的权值为c的单向边。
这样spfa就可以了。
注意一般的spfa用队列实现更稳定,效果更好。
 
//spfa用队列实现一般较快
//主要是一个建图的构思(是不是学完网络流会领会更多呢)

#include <stack>
#include <queue>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 100000;

int layer[maxn+10];

struct
{
    int to;
    int w;
    int next;
}edge[maxn*6+10];
//点的编号1..n 每层再安排一个出点n+1..n*2 一个入点n*2+1..n*3
int head[maxn*3+10];
int vis[maxn*3+10];
int dis[maxn*3+10];

int main()
{
    int t,k=1;
    scanf("%d",&t);
    while(t--)
    {
        int n,m,c;
        scanf("%d%d%d",&n,&m,&c);
        for(int i=1;i<=n;i++)
            scanf("%d",layer+i);

        //建边
        memset(head,-1,sizeof(head));
        int cnt=0;
        for(int i=0;i<m;i++)
        {
            int a,b,w;
            scanf("%d%d%d",&a,&b,&w);
            edge[cnt].to=b;edge[cnt].w=w;edge[cnt].next=head[a];head[a]=cnt++;
            edge[cnt].to=a;edge[cnt].w=w;edge[cnt].next=head[b];head[b]=cnt++;
        }
        //每层安排一个入点一个出点
        for(int i=1;i<=n;i++)
        {
            int a,b,w;
            a=i;b=n+layer[i];w=0;
            edge[cnt].to=b;edge[cnt].w=w;edge[cnt].next=head[a];head[a]=cnt++;
            a=n*2+layer[i];b=i;w=0;
            edge[cnt].to=b;edge[cnt].w=w;edge[cnt].next=head[a];head[a]=cnt++;
        }
        //额外安排的点相邻是C为代价的
        for(int i=1;i<n;i++)
        {
            int a,b,w;
            a=n+i;b=n*2+i+1;w=c;
            edge[cnt].to=b;edge[cnt].w=w;edge[cnt].next=head[a];head[a]=cnt++;
            a=n+i+1;b=n*2+i;w=c;
            edge[cnt].to=b;edge[cnt].w=w;edge[cnt].next=head[a];head[a]=cnt++;
        }
        //printf("11111
");

        //spfa开跑!
        memset(vis,0,sizeof(vis));
        memset(dis,-1,sizeof(dis));
        queue<int> s;
        s.push(1);
        vis[1]=1;
        dis[1]=0;
        while(!s.empty())
        {
            int p=s.front();s.pop();
            vis[p]=0;
            //printf("%d
",p);
            for(int i=head[p];i!=-1;i=edge[i].next)
            {
                int v=edge[i].to,w=edge[i].w;
                if(dis[v]==-1||dis[v]>dis[p]+w)
                {
                    dis[v]=dis[p]+w;
                    if(!vis[v])
                        s.push(v),vis[v]=1;
                }
            }
        }
        //printf("22222
");

        printf("Case #%d: %d
",k++,dis[n]);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/acboyty/p/9648525.html