hdoj 1874 通畅工程续 (最短路)
来源:互联网 发布:linux 复制目录及文件 编辑:程序博客网 时间:2024/06/09 17:32
Problem Description
某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。
现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。
现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。
Input
本题目包含多组数据,请处理到文件结束。
每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。
接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。
每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。
接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。
Output
对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1.
Sample Input
3 30 1 10 2 31 2 10 23 10 1 11 2
Sample Output
2-1
/*dijkstra算法:其实它长得和prime算法非常像,不同的是,prime算法里每次更新的lowcost集合是红点集与蓝点集之间的最小权值路径,然后将这些最小路径里再找最小的一个加入ans,最后的这个ans就是生成树的权值。而dijkstra里,dis更新的是从开始点到其他每个点的最短长度。开始时dis先初始化为无穷大,然后从开始点出发,找出一个权值最小的路,将其对应的点标记为vis=1(第一次循环时这个点必定是开始点),换句话说就是把这个点加入了红点集。每次找的新点:看看是从原先的路过去近,还是经过红点集中的点再过去近。如果后者,就更新dis,找出dis中最小的,对应的点就是新点。之前学数据机构模拟手算的时候我还有个疑问,就是假如红点集中的点是1,2,3,那么我找到4的距离的时候,是比较从1到4还是从1到2到4还是从1到2到3到4呢?这样的话点越多就越不好判断了呀。其实算法中,dis是一直更新的,保存的不一直是1-4距离,而是每加入一个点,就看看是不是更短。例如:加入2之后,就比较1-4和1-2-4,发现后者更小,那么dis就变成了1-2-4.又加入了3,就比较1-2-4(就是此时的dis)和1-2-3-4.也就是看dis[j]与dis[k]+map[k][j](这里的j为当前考察的点,即4,k是刚刚加入红点集的新点),所以dis保存的一直是已存所有路径中最短的。这里的道理和lowcost一样。*/#include <stdio.h>#include <string.h>#define INF 0xfffffffint map[210][210], vis[210], s, t, n, m, dis[210];int dijkstra(){ int i, j, k, min = INF; dis[s] = 0; for(i = 0 ; i < n ; i++) { min = INF; for(j = 0 ; j < n ; j++) { if(!vis[j] && min > dis[j]) { min = dis[j]; k = j; } } vis[k] = 1; for(j = 0 ; j < n ; j++) { if(!vis[j] && dis[j] > (dis[k] + map[k][j]))//比较dis dis[j] = dis[k] + map[k][j]; } } if(!vis[t]) return -1; return dis[t];}int main(){ int i, j, a, b, x; while(~scanf("%d %d", &n, &m)) { for(i = 0 ; i < n ; i++) { dis[i] = INF;//之前忘了把最短距离先初始化为无穷大 for(j = 0 ; j < n ; j++) map[i][j] = INF; }memset(vis, 0, sizeof(vis)); for(i = 0 ; i < m ; i++) { scanf("%d %d %d", &a, &b, &x); if(x < map[a][b]) map[a][b] = map[b][a] = x; } scanf("%d %d", &s, &t); printf("%d\n", dijkstra()); } return 0;}
//bellman-ford:#include <stdio.h>#include <string.h>#define INF 0xffffffftypedef struct{ int u, v, cost;}node;node edge[10050];int s, t, n, m, dis[210];int ford(){ int i, j; dis[s] = 0; for(i = 0 ; i < n-1 ; i++) for(j = 0 ; j < 2*m ; j++) { if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) dis[edge[j].v] = dis[edge[j].u] + edge[j].cost; } if(dis[t] == INF) return -1; return dis[t];}int main(){ int i; while(~scanf("%d %d", &n, &m)) { for(i = 0 ; i < n ; i++) { dis[i] = INF;//之前忘了把最短距离先初始化为无穷大 } for(i = 0 ; i < m ; i++) { scanf("%d %d %d", &edge[i].u, &edge[i].v, &edge[i].cost); edge[m+i].v = edge[i].u; edge[m+i].u = edge[i].v; edge[m+i].cost = edge[i].cost; } scanf("%d %d", &s, &t); printf("%d\n", ford()); } return 0;}
问题描述
给定一个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 -1
2 3 -1
3 1 2
样例输出
-1
-2
-2
数据规模与约定
对于10%的数据,n = 2,m = 2。
对于30%的数据,n <= 5,m <= 10。
对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保证从任意顶点都能到达其他所有顶点。
/*spfa算法:形式和广搜很像。虽然效率不如dijkstra高,但它可以处理有负权的情况。(dijkstra在边有负权的情况下求出来的最短路是错误的)哎呀,这种方法在我第一次见到最短路并且当时还不知道dij算法的时候就想到过了,只是没有付诸实施……不过我当时只想到了邻接矩阵的算法,就是打一个邻接矩阵,像走迷宫一样广搜。搜到一个点就跳到其对应的行上继续搜。这里由于n太大,所以邻接矩阵不可行,得用邻接表存储。这里的邻接表存储是模拟了链表,用head数组表示从同一个点出发的不同的边连成的线性表。如head[2]:2-3->2-4->-1。其中head数组的下标是谁就是这个表的起边都是谁,如上边那个例子就是这个线性表的起边都是2,但终边不相同。head的内容是保存了当前线性表的头结点,在这里是2-3边的序号。计算过程就是从起点开始,选择它所在的那一条线性表,逐个松弛。其中能松弛的,就说明这条路被更新了,那么其对应的终点就要入队,意思是到这条路终点的那一段路被更新得更小了,所以这个终点连着的其它点可能也要被更新。这里需要注意的一点就是标记。Bellman-Ford算法中没有这一点,不管三七二十一都进行判断松弛操作。而这里是对它进行了改进,防止了多余的判断松弛。(松弛操作是都有的,能松就松,但松了以后不一定再入队了)例如:2-4->2-3->-1, 3-4->-1。松弛了2-4,把4入了队。再下一个3-4中,也进行了松弛,但这里的4就不需要入队了。防止了多余的操作。出队的点可以再入队。所以每出一个点,就把vis改回0.*/#include <stdio.h>#include <queue>#include <string.h>#define l 20005#define inf 0xfffffffusing namespace std;struct e{ int x, y, w, next;}edge[l*10];int n, m, head[l], vis[l], dis[l];queue <int> q;void spfa(int choose){ int u, v, i; vis[choose] = 1; dis[choose] = 0; q.push(choose); while(!q.empty()) { u = q.front(); q.pop(); vis[u] = 0;//出队的点标记回未访问。只有出过队的点才有机会再入队。所以标记数组vis必须有。 for(i = head[u] ; i != -1 ; i = edge[i].next) { v = edge[i].y; if(dis[v] > dis[u] + edge[i].w) { dis[v] = dis[u] + edge[i].w; if(!vis[v]) { q.push(v); vis[v] = 1; } } } }}int main(){ int i, x, y, w; scanf("%d %d", &n, &m); for(i = 1 ; i <= n ; i++) { dis[i] = inf; head[i] = -1;//head[i]表示从点i出去的最后那一条边的序号。 vis[i] = 0; } for(i = 0 ; i < m ; i++) { scanf("%d %d %d", &x, &y, &w); edge[i].x = x; edge[i].y = y; edge[i].w = w; edge[i].next = head[x];//模拟链表。head数组的下标表示是属于哪个点的那条串,内容是上一次的属于这条串的边的序号。 head[x] = i;//移动头结点为新的序号。 } spfa(1); for(i = 2 ; i <= n ; i++) printf("%d\n", dis[i]); return 0;}
0 0
- hdoj 1874 通畅工程续 (最短路)
- hdu 1874 通畅工程续(最短路模板)
- HDOJ 1874 畅通工程续(最短路)
- HDOJ-1874-畅通工程续(最短路)
- HDOJ 1874 畅通工程续 (最短路)
- HDOJ/HDU---1874 畅通工程续 最短路(dijkstra)
- HDOJ 1874 畅通工程续(最短路 - dijsktra算法)
- HDOJ 1874 畅通工程续(最短路--dijkstra)
- HDOJ 1874 畅通工程续(最短路)
- HDOJ 1874 畅通工程续 (最短路之SPFA)
- HDOJ 1874 畅通工程续 (最短路之floyd)
- HDOJ 1874 畅通工程续 (最短路)
- hdoj 1874 畅通工程续 (最短路)
- HDOJ 1874 畅通工程续(最短路)
- HDOJ 1874 畅通工程续(最短路)
- HDU 1874 通畅工程续(Dijkstra)
- hdoj 1232 通畅工程
- HDOJ 畅通工程续 1874【简单最短路】
- java软件复杂运算,同时显示进度条的一种方法
- 一款桌面英语翻译软件介绍
- Oracle SQL*Loader
- Linux的ACL权限
- Leetcode:Path Sum 菜鸟解法
- hdoj 1874 通畅工程续 (最短路)
- Java中Runnable和Thread的区别
- 00-自测1. 打印沙漏(20)
- 阿里云cos,memcached无法使用
- oracle使用pagesize命令
- 黑马程序员--对File类的理解
- 记录一些链接,方便自己有空的时候慢慢查看
- 64位Win8安装Oracle12C临时位置权限错误解决方案
- 30行C代码实现贪吃蛇