题目76:最短路

//http://ac.jobdu.com/problem.php?cid=1040&pid=75
//主要掌握弗洛伊德算法,三重循环,理解记忆
#include <stdio.h>
int ans[101][101];                 //初始值是该图的邻接矩阵
int main()
{
	int n,m,i,j,k;
	while (scanf("%d%d",&n,&m)!=EOF &&(n!=0 &&m !=0))
	{
		for (i=1;i<=n;i++)
		{
			for (j=1;j<=n;j++)
			{
				ans[i][j]=-1;       //邻接矩阵初始化,-1代表无穷           
			}
			ans[i][i]=0;           //自己到自己的长度为0
		}
		
		while (m--)
		{
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			ans[a][b]=ans[b][a]=c;          //无向图,边赋值两次
		}

		for (k=1;k<=n;k++)                //k循环到n,允许经过的中间节点编号<=k
		{
			for (i=1;i<=n;i++)
			{
				for (j=1;j<=n;j++)
				{
					if (ans[i][k]==-1 || ans[k][j]==-1)  //i到k或k到j有一个不通,保持原值
					{
						continue;
					}
					if (ans[i][j]==-1 || ans[i][k]+ans[k][j]<ans[i][j]) 
					{//i到j不可达,或经过k路径变短.前提就是i到k且k到j通
                         ans[i][j]=ans[i][k]+ans[k][j];   
					}
				}
			}
		}
       printf("%d\n",ans[1][n]);

	}
	return 0;
}
/*
对于上机测试,结点树不能大于200
若两点间有多条边时,选择最小的边赋给邻接矩阵
若图用邻接表存储,转换为邻接矩阵
算法得到所有节点间的最短路径,适用于求多对节点间的最短路径
*/

使用dijkstra算法

#include <stdio.h>
#include <vector>
using namespace std;

struct E				     //邻接表中链表元素结构体(边)
{
	int next;			    //直接相邻节点
	int c;			    	//该边权值
};

vector <E> edge[101];      //vector作邻接链表,结点不超过100  
bool mark[101];            //mark[i]为true时,表示结点i的最短路径长度已经得到,结点i加入集合k
int dis[101];             //mark[i]=true时,从1到i的最短路径长度
                          //mark[i]=false时,从1到k中某点的最短路径长度再加上从该点到i的距离

int main()
{
	int n,m,i,j;
	while (scanf("%d%d",&n,&m)!=EOF && n!=0 &&m!=0)
	{
       for (i=1;i<=n;i++)
       {
		   edge[i].clear();            //初始化邻接链表
       }
	   while (m--)                    //根据输入边信息,建立邻接表
	   {
		   int a,b,c;
		   scanf("%d%d%d",&a,&b,&c);
		   E tmp;                       //新建节点
		   tmp.c=c;
		   tmp.next=b;
		   edge[a].push_back(tmp);      //将该边加入结点a的边表,作为邻接边
		   tmp.next=a;
		   edge[b].push_back(tmp);      //加入结点b的边表(因为无向图所以加两次)
	   }	   
		   for (i=1;i<=n;i++)          //初始化
		   {
			   dis[i]=-1;              //-1表示不可达 
			   mark[i]=false;          //所有节点不属于集合k
		   }
		   dis[1]=0;            
		   mark[1]=true;              //1到1最近,长度为0,1加入结合k
		   int newP=1;                 //集合k中新加入的点为结点1
		   for (i=1;i<n;i++)          // 循环n-1次,按路径递增顺序确定其他点的最短路径
			{
               for (j=0;j<edge[newP].size();j++)  //遍历新加入k的结点的直接相邻边
               {
                  int t=edge[newP][j].next;        //该边的另一节点
				  int c=edge[newP][j].c;
				  if (mark[t]==true)             //另一节点也属于k,跳过
				  {
					  continue;
				  }
				  if (dis[t]==-1 || dis[t]>dis[newP]+c)  //该节点尚不可达或有更短路径
				  {
                     dis[t]=dis[newP]+c;
				  }
				}
				  int min=123123123;                 //最小值初始化为一个大数
				  for (j=1;j<=n;j++)                 //遍历所有节点
				  {
					  if (mark[j]==true)			//若其属于结合k,跳过
					  {
						  continue;
					  }
					  if (dis[j]==-1)			   //若该节点仍不可达(肯定不最短),跳过
					  {
						  continue;
					  }
					  if (dis[j]<min)			  //依次比较找最短
					  {
						  min=dis[j];            //暂时保存最短
						  newP=j;                //暂时保存newP最短边的另一结点
					  }
				  }
				  mark[newP]=true; // 该点加入集合k,dis[newP]表示从1到newP的最短距离
               
			}


	   printf("%d\n",dis[n]);
	}
	return 0;
}
/*
mark[i]=true时,结点i属于集合k,dis[i]表示从1到i的最短路径长度
mark[i]=false时,结点i不属于集合k,dis[i]表示从1到k中某点的最短路径长度再加上从该点到i的最短距离

想想一个有向图的求解最短路径的做法,先初始化,再将源点加入,更新相邻边,找到最短
更新newP,再找相邻边,再找其最短,更新newP。。。
*/




 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值