最短路

问题描述

给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路(顶点从1到n编号)。

输入格式

第一行两个整数n, m。

接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。

输出格式
共n-1行,第i行表示1号点到i+1号点的最短路。
样例输入
3 3
1 2 -1
2 3 -1
3 1 2
样例输出
-1
-2
数据规模与约定

对于10%的数据,n = 2,m = 2。

对于30%的数据,n <= 5,m <= 10。

对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保证从任意顶点都能到达其他所有顶点。


今天犯了几个十分低级的错误。

在双重循环里面用了同一个循环变量。

在开始用堆做这个题的时候卡了一会,不知道如何在堆中能直接索引元素,后来想到堆中只放数组下标,然后问题基本解决。

之后就是痛苦的Debug过程,因为堆中只有数组下标,所以堆排序的操作复杂到必然出错,结果花了几个小时才理清头绪。

又学了一遍堆排序,但总是记不住,不知道还要学几次。。。

  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<stdlib.h>
  4. #define N 20020
  5. #define INF 2147483640
  6. typedef struct Node
  7. {
  8.     int v;
  9.     int d;
  10.     struct Node *next;
  11. } Node, *Np;
  12. Np list[N];
  13. void insert(int a, int b, int c)
  14. {
  15.     Np np = malloc(sizeof(Node));
  16.     np->d = b;
  17.     np->v = c;
  18.     np->next = list[a];
  19.     list[a] = np;
  20. }
  21. typedef struct Data
  22. {
  23.     int v;
  24.     int rp;
  25. }Data;
  26. Data data[N];
  27. int heap[N];
  28. void swap(int a, int b)
  29. {
  30.     int t = heap[a];
  31.     heap[a] = heap[b];
  32.     heap[b] = t;
  33.     data[heap[a]].rp = a;
  34.     data[heap[b]].rp = b;
  35. }
  36. void up(int x)
  37. {
  38.     while(x > 1)
  39.     {
  40.         if(data[heap[x / 2]].v > data[heap[x]].v)
  41.         {
  42.             swap(x, x / 2);
  43.             x /= 2;
  44.         }
  45.         else
  46.         {
  47.             break;
  48.         }
  49.     }
  50. }
  51. void down(int x, int len)
  52. {
  53.     while(x * 2 <= len)
  54.     {
  55.         int a = x * 2;
  56.         if(a + 1 <= len && data[heap[a]].v > data[heap[a + 1]].v)
  57.         {
  58.             a = a + 1;
  59.         }
  60.         if(data[heap[x]].v > data[heap[a]].v)
  61.         {
  62.             swap(x, a);
  63.             x = a;
  64.         }
  65.         else
  66.         {
  67.             break;
  68.         }
  69.     }
  70. }
  71. int main(void)
  72. {
  73.     int i, n, m;
  74.     scanf("%d%d", &n, &m);
  75.     for(i = 0; i < m; i++)
  76.     {
  77.         int a, b, c;
  78.         scanf("%d%d%d", &a, &b, &c);
  79.         insert(a, b, c);
  80.     }
  81.     for(i = 2; i <= n; i++)
  82.     {
  83.         heap[i - 1] = i;
  84.         data[i].v = INF;
  85.         data[i].rp = i - 1;
  86.     }
  87.     Np p = list[1];
  88.     while(p != NULL)
  89.     {
  90.         data[p->d].v = p->v;
  91.         up(data[p->d].rp);
  92.         p = p->next;
  93.     }
  94.     int count = n - 1;
  95.     while(count > 1)
  96.     {
  97.         int base = heap[1];
  98.         swap(1, count--);
  99.         down(1, count);
  100.         Np p = list[base];
  101.         while(p != NULL)
  102.         {
  103.             int t = p->v + data[base].v;
  104.             if(t < data[p->d].v)
  105.             {
  106.                 data[p->d].v = t;
  107.                 up(data[p->d].rp);
  108.             }
  109.             Np temp = p;
  110.             p = p->next;
  111.             free(temp);
  112.         }
  113.     }
  114.     for(i = 2; i <= n; i++)
  115.     {
  116.         printf("%d\n", data[i].v);
  117.     }
  118.     return 0;
  119. }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值