【高手回避】poj3268,一道很水的dijkstra算法题

来源:互联网 发布:大数据探索性分析 编辑:程序博客网 时间:2024/05/01 19:55

网上看的大多是转置矩阵,然后套用两次dijkstra算法

个人认为,转置一个n*n的矩阵在时间方面是很不划算的,虽然dijkstra算法本身的复杂度就是O(n^2)(当然你能用堆优化达到O((n + m) * log n),用斐波那契堆优化可以达到O(m + n * log n))……但是个人认为这道题完全没有必要转置这个矩阵。

当牛去第x个牧场的时候,我们不太习惯这种模式,一般都是单源多终点的题,这次来个多元单终点的。。。其实算法是一样的,就是看对Dijstra算法的理解度。

dijkstra算法就是不断维护并更新dist[n]的最小值,那么(我个人比较偏向于tab缩进,tab宽度=4):

#include <cstdio>#include <cstring>#include <climits>#define MAXN 1001         // 这里可以用1000,但是为了保险还是给个1001吧unsigned to_dist[MAXN];   // 牛要过去时的dist[n]unsigned back_dist[MAXN]; // 牛回来时的dist[n]unsigned mp[MAXN][MAXN];bool s[MAXN];int main(int argc, char* argv[]){int n, m, x, i, j, a, b, t, k; // n,m,x都是题目给的,i,j是临时变量(我懒得每for就临时变量)unsigned mins;while (scanf("%d%d%d", &n, &m, &x) != EOF){memset(mp, 0xff, sizeof(mp)); // 默认边长为0xffffffff,unsigned int的最大值memset( s,    0, n);          // 这里之所以是n是因为我们知道bool占一个字节while (m-- && scanf("%d%d%d", &a, &b, &t))mp[a - 1][b - 1] = t;mp[x - 1][x - 1] = 0;// 先做不常见的倒过来行走for (i = 0; i < n; ++i)to_dist[i] = mp[i][x - 1]; // 倒过来赋dist[n]的值即可,从每个起点到x(即数组里的x-1)s[x - 1] = true;for (i = 1; i < n; ++i) // 这里可以使用while(1),因为在运行了n-1次后必定终止{mins = UINT_MAX;k = -1;for (j = 0; j < n; ++j){if (!s[j] && mins > to_dist[j]){mins = to_dist[j];k = j;}}if (k == -1)break;s[k] = true;for (j = 0; j < n; ++j){// 倒过来思考即可,如果从j到k有路而且dist[j]比从j到k再通过k到x的路径要长,就更新它if (!s[j] && mp[j][k] != UINT_MAX && to_dist[j] > mins + mp[j][k])to_dist[j] = mins + mp[j][k];}}memset(s, 0, n); // 计算返回的dist[n]前更新s[n],下面都是套公式,不解释了for (i = 0; i < n; ++i)back_dist[i] = mp[x - 1][i];s[x - 1] = true;for (i = 1; i < n; ++i){mins = UINT_MAX;k = -1;for (j = 0; j < n; ++j){if (!s[j] && mins > back_dist[j]){mins = back_dist[j];k = j;}}if (k == -1)break;s[k] = true;for (j = 0; j < n; ++j){if (!s[j] && mp[k][j] != UINT_MAX && back_dist[j] > mins + mp[k][j])back_dist[j] = mins + mp[k][j];}}mins = 0;for (i = 0; i < n; ++i){if (mins < to_dist[i] + back_dist[i])mins = to_dist[i] + back_dist[i];}printf("%u\n", mins); // 注意这里的输出格式,不然WA别怪我}return 0;}


0 0