zoukankan      html  css  js  c++  java
  • HDU 4725 The Shortest Path in Nya Graph(spfa+虚拟点建图)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4725

    题目大意:有n层,n个点分布在这些层上,相邻层的点是可以联通的且距离为c,还有额外给出了m个条边,求1号点到n号点的最短距离,若无法到达则输出“-1”。

    解题思路:最短路问题,主要是建图很难。如果按常规建法,用邻接表存每层的节点编号然后在建边肯定会超时,因为如果点只分布在两个层上,那建边的复杂度就是O(n^2)了。所以要改变一下思路,可以用n个虚拟点来代表n层,把连到该层的点都连接到虚拟点上,同一层花费为0,不同层花费为c。但是还需要一点处理,不然这样的话同一层的点的花费就会变成0,原本可能不可达的变得可达。这是我从别人博客看来的两种方法(出处):

    A.每层拆两个点,一个点管入,一个点管出,这样的话同层的点不会回到同层的另外一个点上。

    B.每层拆一个点,这个点只管入,而处于该层的点则向左右两层虚拟点相连。

    我用的是方法B,建了2n个点(有n个是虚拟点),边数大概为5n条(点和点2n,点和相邻层2n,虚拟点到同层的点n)

    代码:

     1 #include<iostream>
     2 #include<queue>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 const int N=2e5+5;
     7 const int INF=0x3f3f3f3f;
     8 
     9 struct node{
    10     int to,next,w;
    11 }edge[5*N];
    12 
    13 int n;
    14 int idx,head[N],dis[N],layer[N];//layer[i]记录第i个点所在的层 
    15 bool vis[N],sign[N];//sign[i]记录第i层是否有点
    16 
    17 void init(){
    18     idx=1;
    19     memset(head,-1,sizeof(head));
    20 }
    21 
    22 void addEdge(int u,int v,int w){
    23     edge[idx].to=v;
    24     edge[idx].w=w;
    25     edge[idx].next=head[u];
    26     head[u]=idx; 
    27     idx++;
    28 }
    29 
    30 void spfa(int s){
    31     memset(dis,0x3f,sizeof(dis));
    32     memset(vis,false,sizeof(vis));
    33     dis[s]=0;
    34     queue<int>q;
    35     q.push(s);
    36     while(!q.empty()){
    37         int k=q.front();
    38         q.pop();
    39         vis[k]=false;
    40         for(int i=head[k];i!=-1;i=edge[i].next){
    41             node t=edge[i];
    42             if(dis[k]+t.w<dis[t.to]){
    43                 dis[t.to]=dis[k]+t.w;
    44                 if(!vis[t.to]){
    45                     q.push(t.to);
    46                     vis[t.to]=true;
    47                 }
    48             }
    49         }
    50     }
    51 }
    52 
    53 int main(){
    54     int t,cas=0;
    55     scanf("%d",&t);
    56     while(t--){
    57         init();
    58         memset(sign,false,sizeof(sign));
    59         int m,c;
    60         scanf("%d%d%d",&n,&m,&c);
    61         for(int i=1;i<=n;i++){
    62             scanf("%d",&layer[i]);
    63             sign[layer[i]]=true;
    64         }
    65         for(int i=1;i<=n-1;i++){        //相邻层的虚拟点建边
    66             if(sign[i]&&sign[i+1]){        //当两个相邻层都有点才建边 
    67                 addEdge(i+n,i+n+1,c);
    68                 addEdge(i+n+1,i+n,c);
    69             } 
    70         }
    71         for(int i=1;i<=n;i++){            //虚拟点到同一层的点建边 
    72             addEdge(layer[i]+n,i,0);     
    73             if(layer[i]>1)                //点和相邻层的虚拟点建边 
    74                 addEdge(i,layer[i]+n-1,c);
    75             if(layer[i]<n)
    76                 addEdge(i,layer[i]+n+1,c);
    77         }
    78         
    79         for(int i=1;i<=m;i++){
    80             int u,v,w;
    81             scanf("%d%d%d",&u,&v,&w);
    82             addEdge(u,v,w);
    83             addEdge(v,u,w);
    84         }
    85         spfa(1);    
    86         if(dis[n]<INF)
    87             printf("Case #%d: %d
    ",++cas,dis[n]);
    88         else
    89             printf("Case #%d: -1
    ",++cas);
    90     }
    91     return 0;
    92 }
  • 相关阅读:
    侧滑的一个注意
    viewpager+fragment结合
    webview
    动画
    <context:annotation-config> 和 <context:component-scan>的区别
    spring mvc 原理及应用
    HDU
    使用Log4Net将系统日志信息记录到记事本和数据库中
    chromium for android GPU进程结构分析
    【云图】怎样制作全国KTV查询系统?
  • 原文地址:https://www.cnblogs.com/fu3638/p/7882019.html
Copyright © 2011-2022 走看看