hdu 4725 有点深度的最短路

题意:有n个点 , m条无向边 , 每条边都是有权值 , 并且 , 每个点属于一个楼层 , 相同楼层之间可以通过 , 但是要花费 c , 求 1 到 n的最小花费。

解法:刚开始做得时候 , 我是直接把两个相邻楼层之间的点建立一条无向边 , 权值为c , 但是一直TEL , 一开始一直不明白是为什么 , 看了大牛的代码是通过把每个点拆成3个点来做 , 一开始也没明白 , 为什么我这么做会超时 , 我还一直在优化最短路算法 。 后来突然明白 , 我那种方法 , 主要时间不是花在找最短路上 , 而是在建图上面 , 因为 , 我们首先要找到当前点和哪些点的楼层是相邻的 , 这就需要遍历所有点 , 由于有10^5个点 ,那就肯定要超时了 。 而大神那种做法 , 对于建图只需要O(1)的常数时间 , 这就是我TEL的原因。

建图:对于每个点 , 拆成3个点:1、本身 , 2、看做是层下的点,只跟当前点的上一层相连 , 2、看做是层上点 , 只跟当前点的下一层相连 , 并且都是单向边。

代码:
#include
#include
#include
#include
#include
#include
using namespace std;

#define maxn 300100
#define INF  2000000000
#define min(x ,y) (x)<(y)?(x):(y)

struct node
{
      int u;
      int d;
}e;

int pre[maxn] ;
int  dist[maxn];
vectorgrap[maxn];
int n , m , c;
int xy;


void init()
{
      for(int i = 1; i <= 3*n; i++)
              grap[i].clear();
}


struct node1
{
      int u;
      int d;
      bool operator < (const node1 &rhs)const
      {
              return d > rhs.d;
      }
}f;

void addedge(int x , int y , int z)
{
      e.u = y , e.d = z;
      grap[x].push_back(e);
 
}

void dijkstra()
{
      priority_queueq;
      f.u = 1 , f.d  = 0;
      q.push(f);
     
      int i ;
     
      for(i = 1; i <= 3*n; i++)  dist[i] = INF;
      dist[1] = 0;
      memset(pre , 0 , sizeof(pre));
     
      while(!q.empty())
      {
              f = q.top(); q.pop();
              int u = f.u;//cout<<u<<endl;
              if(u == n)  return ;
              if(pre[u])  continue;
              pre[u] = 1;
              for(i = 0; i < grap[u].size(); i++)
              {
                      e = grap[u][i];
                      if(dist[e.u] > dist[u]+e.d)
                      {
                              dist[e.u] = dist[u]+e.d;
                              f.u = e.u;
                              f.d = dist[e.u];
                              q.push(f);
                      }
              }
      }
     
}


int main()
{
//      cout<<INF<<endl;
      int t , tcase = 1;
      cin>>t;
      while(t--)
      {
              scanf("%d %d %d" , &n , &m , &c);
              init();

              int i , x , y ;
              int z;
              for(i = 1;i <= n;i++)
              {
                      scanf("%d",&xy);
                      addedge(i,n + 2*xy - 1,0);
                      addedge(n + 2*xy ,i,0);

              }
              for( i = 1;i < n;i++)
              {
                      addedge(n + 2*i-1,n + 2*(i+1),c);
                      addedge(n + 2*(i+1)-1,n + 2*i,c);
              }
              while(m--)
              {
                      scanf("%d%d%d",&x,&y,&z);
                      addedge(x,y,z);
                      addedge(y,x,z);
              }

              dijkstra();

              if(dist[n] == INF)
              {
                      printf("Case #%d: %d\n" , tcase++ , -1);
              }
              else
              {
                      printf("Case #%d: %d\n" , tcase++ , dist[n]);
                      //cout<<dist[n]<<endl;
              }

      }
      return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值