HDU4725(The Shortest Path in Nya Graph)

题目链接:传送门

题目大意:首先输入n,m,c;n代表点数,m是额外的边,c是层与层之间的权值。然后接下来n个数分别表示第i个点属于哪个层(层与层之间可互通),然后m行,每行三个数        x,y,v,表示点x到y权值为v求点1到点n的最短路。

题目思路:把每个层拆成两个点(点到相应层之间距离为0),注意是拆成两个点,原因很简单,如果只拆成一个点,那么如果点1属于1层,点2也属于1层,那么推出来1与2距离为0,    结果错误,所以拆成两个点,前一个点代表入点(点到层),都一个代表出点(层到点),然后SPFA或者堆优化dijkstra就行。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <cctype>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <climits>
#define lson root<<1,l,mid
#define rson root<<1|1,mid+1,r
#define fi first
#define se second
#define seg int root,int l,int r
#define ping(x,y) ((x-y)*(x-y))
#define mst(x,y) memset(x,y,sizeof(x))
#define mcp(x,y) memcpy(x,y,sizeof(y))
#define Min(x,y) (x<y?x:y)
#define Max(x,y) (x>y?x:y)
using namespace std;
#define gamma 0.5772156649015328606065120
#define MOD 1000000007
#define inf 0x3f3f3f3f
#define N 1000001
#define maxn 300021
typedef long long LL;
typedef pair<int,int> PII;

int vis[maxn],d[maxn],head[maxn],n,m,ans;
int a[maxn];
struct Node{
    int to,next,v;
    Node(){}
    Node(int a,int b,int c):to(a),next(b),v(c){}
}node[N];int hcnt=0;

void add(int x,int y,int v){  ///加边
    node[hcnt]=Node(y,head[x],v);
    head[x]=hcnt++;
}

void spfa(){
    mst(d,inf); d[1]=0;
    mst(vis,0); vis[1]=1;
    deque<int>q;         ///deque优化
    q.push_back(1);
    while(!q.empty()){
        int s=q.front();q.pop_front();
        vis[s]=0;
        for(int i=head[s];~i;i=node[i].next){
            int e=node[i].to;
            if(d[e]>d[s]+node[i].v){
                d[e]=d[s]+node[i].v;
                if(!vis[e]){
                    if(!q.empty()&&d[e]<d[q.front()])
                        q.push_front(e);
                    else
                        q.push_back(e);
                    vis[e]=1;
                }
            }
        }
    }
    if(d[n]==inf) ans=-1;
    else ans=d[n];
}

int main(){
    int i,j,group,x,y,v,Case=0;
    scanf("%d",&group);
    while(group--){
        mst(head,-1);
        hcnt=0;
        scanf("%d%d%d",&n,&m,&v);
        for(i=1;i<=n;++i){
            scanf("%d",&x);
            add(i,n+2*x-1,0);    ///加入边
            add(n+2*x,i,0);      ///加出边
        }
        for(i=1;i<n;++i){
            add(n+2*i-1,n+2*(i+1),v);    ///注意合并顺序,入边与出边相对应
            add(n+2*(i+1)-1,n+2*i,v);    ///这样才能避免同一层的点距离为0的情况
        }
        while(m--){
            scanf("%d%d%d",&x,&y,&v);
            add(x,y,v);
            add(y,x,v);
        }
        spfa();
        printf("Case #%d: %d
",++Case,ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Kurokey/p/5467041.html