poj1125 Floyd算法
问题描述
众所周知,证券经纪业依靠的就是过度的传言。您需要想出股票经纪人中传播假情报的方法,让您的雇主在股票市场的占据优势。为了获得最大的效果,你必须蔓延最快的方式谣言。
不幸的是你,股票经纪人信息只信任他们的“可靠来源”,这意味着你在你传播谣言之前必须考虑到他们的接触结构。它需要特定股票经纪人和一定的时间把谣言传递给他的每一位同事。你的任务将是写一个程序,告诉您选择哪一个股票经纪人作为谣言的出发点和所花费多少时间将谣言扩散到整个社会的股票经纪人。这一期限是衡量过去的人收到信息所需的时间。
输入
你的程序包含多组股票经纪人的输入数据。每组以股票经纪人的人数开始。接下来的几行是每个经纪人与其他人接触的一些信息,包括这些人都是谁,以及将讯息传达到他们所需的时间。每个经纪人与其他人接触信息的格式如下:开头的第一个数表示共有n个联系人,接下来就有n对整数。每对整数列出的第一个数字指的是一个联系人(例如,一个'1'是指编号1的人),其次是在传递一个信息给那个人时所采取分钟的时间。没有特殊的标点符号或空格规则。
每个人的编号为1至经纪人数目。所花费的传递时间是从1到10分钟(含10分种)。股票经纪的人数范围是从1到100。当输入股票经纪人的人数为0时,程序终止。
输出
在对于每一组数据,你的程序必须输出一行,包括的信息有传输速度最快的人,以及在最后一个人收到消息后,所总共使用的时间(整数分钟计算)。
你的程序可能会收到的一些关系会排除一些人,也就是有些人可能无法访问。如果你的程序检测到这样一个破碎的网络,只需输出消息“disjoint”。请注意,所花费的时间是从A传递消息到B,B传递信息到A不一定是花费同样的传递时间,但此类传播也是可能的。
代码如下:
#include <stdio.h> #include <string.h> #define INF 0x3f3f3f3f //定义了一个无穷大值 //定义了一个计算最大值的运算,注意要加括号, //因为如果不加括号(3+3,4+4),被带入宏定义为3+3>4+4结果就不是预期的了 #define max(a,b) ((a)>(b)?(a):(b)) //定义了一个图 int gra[105][105]; int main() { int n; while(scanf("%d",&n) && n) { int i,j,k; for(i=1;i<=n;i++) for(j=1;j<=n;j++){ gra[i][j]=INF; //初始化所有的点之间的距离为无穷大 } for(j=1;j<=n;j++) { int k; scanf("%d",&k); //接受k个j到其他点的距离,存如gra for(i=1;i<=k;i++) { int a,b; scanf("%d%d",&a,&b); gra[j][a]=b; } } //用floyd算法来计算所有点之间的最短路径 for(k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++) //这里的比较原理为,用k点作为试探点,观察从i到j点的最短距离,如果经过k点 //i到j的距离更短,那么把i到j的距离更新为从i到k再到j的距离 if(gra[i][k] < INF && gra[k][j] < INF && (gra[i][k]+gra[k][j]) <gra[i][j]) gra[i][j]=gra[i][k]+gra[k][j]; //求最段距离,和出发点 int minn=INF,pos=0; for(i=1;i<=n;i++) { int now=-1; //找出从一个点i出发,找出最大值,因为最大值才可能是把所有的节点都遍历完了 for(int j=1;j<=n;j++) { if(i==j)continue; now=max(now,gra[i][j]); } //比较重不同的点i出发,每个点出发走完所有点后的距离与最小值进行比较,如果比他小则可能为最短路径 if(now<minn) { minn=now; //记录最短路径大小 pos=i; //记录出发点 } } if(minn == INF){ printf("disjoint\n"); } else { printf("%d %d\n",pos,minn); } } return 0; }
对Floyd算法的理解:
Floyd算法是一个已多源求最短路径的算法,算出每个节点到其他点的最短距离,
时间复杂度为n的3次方,可以用于求解那些从任意点中选出一个最短的路径出发
的问题,程序实现简单,但不能求解数据量较大的图
可以加入对路径的跟踪:
定义一个数组path[105][105],用于存储从i到j所经过的节点,在初始化时为-1
表示不可达,在接受输入时,在更新gra[i][j]的同时,更新path[i][j] = j;表示从i到j
需要经过j才能到达,在三重循环中,如果gra[i][j] > gra[i][k]+ gra[k][j],则更新
path[i][j] = k,表示从i到j应该经过k到达更近。在输出路径的时候,可以用path[i][j]作为
中间路径,如:v = path[i][j],则i到j为i到v,v到j实现如下:
#include <stdio.h> #include <string.h> #define INF 0x3f3f3f3f //定义了一个无穷大值 //定义了一个计算最大值的运算,注意要加括号, //因为如果不加括号(3+3,4+4),被带入宏定义为3+3>4+4结果就不是预期的了 #define max(a,b) ((a)>(b)?(a):(b)) //定义了一个图 int gra[105][105]; int path[105][105];//定义的存储的路径 int main() { int n; while(scanf("%d",&n) && n) { int i,j,k; for(i=1;i<=n;i++) for(j=1;j<=n;j++){ gra[i][j]=INF; //初始化所有的点之间的距离为无穷大 path[i][j] = -1;//表示不可达 } for(j=1;j<=n;j++) { int k; scanf("%d",&k); //接受k个j到其他点的距离,存如gra for(i=1;i<=k;i++) { int a,b; scanf("%d%d",&a,&b); gra[j][a]=b; path[j][i] = i; //表示从j到i,需要经过i到达 } } //用floyd算法来计算所有点之间的最短路径 for(k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++) //这里的比较原理为,用k点作为试探点,观察从i到j点的最短距离,如果经过k点 //i到j的距离更短,那么把i到j的距离更新为从i到k再到j的距离 if(gra[i][k] < INF && gra[k][j] < INF && (gra[i][k]+gra[k][j]) <gra[i][j]){ gra[i][j]=gra[i][k]+gra[k][j]; path[i][j] = k; //这时应该更新路径,表示i到j应该经过k到达 } //求最段距离minn,和出发点pos,maxend表示每个点到其他点的最大路径的终点,end是最短路径的终点 int minn=INF,pos=0, maxend, end = -1; for(i=1;i<=n;i++) { int now=-1; //找出从一个点i出发,找出最大值,因为最大值才可能是把所有的节点都遍历完了 for(int j=1;j<=n;j++) { if(i==j)continue; if(gra[i][j] > now){ now = gra[i][j]; maxend = j; //最大的路径终点,其实是i遍历玩所有点的最短路径终点 } now=max(now,gra[i][j]); } //比较重不同的点i出发,每个点出发走完所有点后的距离与最小值进行比较,如果比他小则可能为最短路径 if(now<minn) { minn=now; //记录最短路径大小 pos=i; //记录出发点 end = maxend; //当满足最短路径时,才更新终点和起点 } } if(minn == INF){ printf("disjoint\n"); } else { printf("%d %d\n",pos,minn); printf("%d",pos); //打印开始位置 int i = 0;
//改点可达,并且不是终点,并且排除开始点和结束点个数
while(path[pos][end] != -1 && path[pos][end] != end && i < (n-2)){
printf("%d", path[pos][end]);
pos = path[pos][end]; //更改下一个位置,求下一个位置到end的路径
i++;
}
printf("%d\n",end); //打印结束位置
}
}
return 0;
}
当然:如果要输出路径,可以遍历整个矩阵,用类似的方法