HDUOJ1874 畅通工程续 和 NYOJ 115 城市平乱【Dijkstra 算法】

原题链接:nyoj 115:http://acm.nyist.net/JudgeOnline/problem.php?pid=115      hduoj  1874: http://acm.hdu.edu.cn/showproblem.php?pid=1874

  一、Dijkstra 算法的介绍

    Dijkstra 算法,又叫迪科斯彻算法(Dijkstra),
    算法解决的是有向图中单个源点到其他顶点的最短路径问题。
   举例来说,
   如果图中的顶点表示城市,而边上的权重表示著城市间开车行经的距离,
   Dijkstra 算法可以用来找到两个城市之间的最短路径。

二、Dijkstra 的算法实现

Dijkstra 算法的输入包含了一个有权重的有向图 G,以及G中的一个来源顶点 S。
我们以 V 表示 G 中所有顶点的集合,以 E 表示G 中所有边的集合。
(u, v) 表示从顶点 u 到 v 有路径相连,而边的权重则由权重函数 w: E → [0, ∞] 定义。

因此,w(u, v) 就是从顶点 u 到顶点 v 的非负花费值(cost),边的花费可以想像成两个顶点之间的距离。
任两点间路径的花费值,就是该路径上所有边的花费值总和。

已知有 V 中有顶点 s 及 t,Dijkstra 算法可以找到 s 到 t 的最低花费路径(例如,最短路径)。
这个算法也可以在一个图中,找到从一个顶点 s 到任何其他顶点的最短路径。

三、图文解析 Dijkstra 算法

 ok,经过上文有点繁杂的信息,你还并不对此算法了如指掌,清晰透彻。
没关系,咱们来幅图,就好了。请允许我再对此算法的概念阐述下,

Dijkstra算法是典型最短路径算法,用于计算一个节点到其他所有节点的最短路径。
不过,针对的是非负值权边。

主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。
[Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。]

ok,请看下图:

如下图,设A为源点,求A到其他各所有一一顶点(B、C、D、E、F)的最短路径。线上所标注为相邻线段之间的距离,即权值。

(注:此图为随意所画,其相邻顶点间的距离与图中的目视长度不能一一对等)

               Dijkstra无向图

HDUOJ1874 畅通工程续 和 NYOJ 115 城市平乱【Dijkstra 算法】_第1张图片


算法执行步骤如下表

HDUOJ1874 畅通工程续 和 NYOJ 115 城市平乱【Dijkstra 算法】_第2张图片

 是不是对此Dijkstra 算法有不错的了解了。。。讲解就到这里了。。

讲解参考:http://blog.csdn.net/v_JULY_v/article/details/6096981

现在说说oj这两个题:

nyoj  115: 懂了dijkstra 后该题没啥难度了,以暴乱城市为 起点 执行一次  求他到各个城市的最短距离,再找出有部队的城市,找到一个最小路 输出即可。。

代码:

 
#include<stdio.h>
#include<string.h>
int budui[105],ok[1005][1005];
int ac[1005],yi[1005];
int main()
{
	int a,b,c,i,j,N,M;
	int m,P,Q,K,k,min;
	scanf("%d",&K);
	while(K--)
	{
		memset(ok,999999,sizeof(ok));//初始化正无穷大
		memset(ac,0,sizeof(ac));
		memset(yi,999999,sizeof(yi));
		scanf("%d%d%d%d",&N,&M,&P,&Q);
			for(a=1;a<=N;a++)
			scanf("%d",&budui[a]);
	    for(a=1;a<=P;a++)
		{
			scanf("%d%d%d",&i,&j,&k);
            ok[i][j]=k;
			ok[j][i]=k;
		}
		yi[Q]=0;
		ac[Q]=1;
		m=M-1;
		b=Q;
		while(m--)//执行m次,找到暴乱城市到所有城市的最短时间
		{
			for(a=1;a<=M;a++)
			{
				if(ac[a]==0)
				{
					if(yi[a]>yi[b]+ok[a][b])
						yi[a]=yi[b]+ok[a][b];
				}
				
			}
			int min1=9999,loop;
			for(c=1;c<=M;c++)
			{
				if(min1>yi[c]&&ac[c]==0)
				{min1=yi[c];loop=c;}
			}
			ac[loop]=1;
			b=loop;
		}
		 min=9999;
		for(a=1;a<=N;a++)//从有部队的城市中找个最短时间
		{
			if(min>yi[budui[a]])
				min=yi[budui[a]];
		}
		printf("%d\n",min);
	}
}
        

     HDUOJ  1874:

    这个题 有点那个什么。。卡了我很久呀!!!还是题意没搞透彻。。⊙﹏⊙。。先用并查集 来判断 题中的S T,是否可以连通。不会并查集的可看我另一篇讲并查集的博客,自己找一下。若不连通,后面就不用执行了,直接下一次循环。。还有个让人蛋疼的条件就是两个城市之间 可能不止一条路!!就是在赋值时加上一个 i f 判断。。

代码:

#include<stdio.h>
#include<string.h>
int ok[1500][1500];
int ac[1505],yi[1500];
int father[1500];
int find(int x)
{
	while(x!=father[x])
		x=father[x];
	return x;
}
void hebing (int x,int y)
{
	x=find(x);
	y=find(y);
	if(x!=y)
		father[x]=y;
}
int main()
{
	int a,b,c,i,j,N,M;
	int m,k,min;
	while(~scanf("%d%d",&N,&M))
	{
		
		memset(ok,9,sizeof(ok));
		memset(ac,0,sizeof(ac));
		memset(yi,9,sizeof(yi));
		for(a=0;a<N;a++)
			father[a]=a;
	    for(a=1;a<=M;a++)
		{
			scanf("%d%d%d",&i,&j,&k);
			if(ok[i][j]>k)
                 ok[i][j]=k;
			if(ok[j][i]>k)
			     ok[j][i]=k;
			hebing(i,j);
		}
		scanf("%d%d",&i,&j);
		if(find(i)!=find(j))
		{printf("-1\n");continue;}
		yi[i]=0;
		ac[i]=1;
		m=N-1;
		b=i;
		while(m--)
		{
			for(a=0;a<N;a++)
			{
				if(ac[a]==0)
				{
					if(yi[a]>yi[b]+ok[a][b])
						yi[a]=yi[b]+ok[a][b];
				}
				
			}
			int min1=9999999,loop;
			for(c=0;c<N;c++)
			{
				if(min1>yi[c]&&ac[c]==0)
				{min1=yi[c];loop=c;}
			}
			ac[loop]=1;
			b=loop;
			if(b==j)
			{break;}
		}
		 printf("%d\n",yi[j]);
	}
}


你可能感兴趣的:(c,算法,扩展)