您的位置:首页 > 其它

多源最短路->Floyd算法

2016-12-14 16:25 211 查看
//多源最短路  动态规划,状态转移方程map[i,j]:=min{map[i,k]+map[k,j],map[i,j]}
/*
能解决带有负权边的图的最短路径问题。
对于有向图,负权还可以解决,负圈会呈现一定形式(记住:任何算法,带有负圈的最短路径是无解的)。
对于无向图,取的测试样例中有负边,最后结果很奇葩,然后图不变,边的值不变,只是改变点的编号,图中有的两点间的最短距离结果竟然不同......
所以对于有负权/负圈的图的最短路径问题,还是很难处理的
其实无向图中若有负权,算法过程会在负权那里转圈,就像负圈一样
*/
//有向图 此处的存储路径方法不适用于负圈(运行出错)
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define MAXN 100
#define INFINITY 0X7FFFFFFF
int map[MAXN][MAXN];
int path[MAXN][MAXN];
int n,m;
void Init(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i!=j){
map[i][j]=INFINITY;
}
else{
map[i][j]=0;}path[i][j]=0;
}
}
}
}
void PrintPath(int x,int y){
if(path[x][y]){
PrintPath(x,path[x][y]);
cout<<" to ";
}
cout<<y;
}
void Floyd(){for(int t=1;t<=n;t++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(map[i][t]!=INFINITY&&map[t][j]!=INFINITY&&map[i][j]>map[i][t]+map[t][j]){
map[i][j]=map[i][t]+map[t][j];
path[i][j]=t;
}
}
}
}
int main(){
int x,y,w;cin>>n>>m;
Init();
for(int i=1;i<=m;i++){
cin>>x>>y>>w;
map[x][y]=w;
path[x][y]=x;
}
Floyd();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
printf("%d%c",map[i][j],j==n?'\n':' ');
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
printf("%d%c",path[i][j],j==n?'\n':' ');
}
}
cin>>x>>y;//起始PrintPath(x,y);
return 0;
}
/*负圈测试:3 31 3 73 2 -52 1 -10 */

//有向图 此代码可打印负圈路径
#include <stdio.h>
#include <stdlib.h>
#define max 1000000000
int d[1000][1000],path[1000][1000];
int main(){
int i,j,k,m,n;
int x,y,z;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
d[i][j]=max;
path[i][j]=j;
}
for(i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
d[x][y]=z;
}
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
if(d[i][k]+d[k][j]<d[i][j]){
d[i][j]=d[i][k]+d[k][j];
path[i][j]=path[i][k];
}
}

for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
printf("%d%c",d[i][j],j==n?'\n':' ');
int f,en;
scanf("%d%d",&f,&en);
do{
printf("%d->",f);
f=path[f][en];
}while(f!=en);
printf("%d\n",en);
return 0;
}
//path[i][j]为从i到j最短路径下一步走哪里
//此处path原理为当前点先到下一个点,再去处理下一个点到终点的路径,path[下一个点][j]为下一个点到j最短路径下一步走哪里
//每一步保证是最短的(贪心),最后也肯定是最短路径

//无向图 全是正的正常,有负的就乱套:数不一样,有负的就打印不出来
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define MAXN 100
#define INFINITY 0X7FFFFFFF
int map[MAXN][MAXN];
int path[MAXN][MAXN];
int n,m;
void Init(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i!=j){
map[i][j]=INFINITY;
}
else{
map[i][j]=0;
}
path[i][j]=0;
}
}
}
void PrintPath(int x,int y){
if(path[x][y]){
PrintPath(x,path[x][y]);
cout<<" to ";
}
cout<<y;
}
void Floyd(){
for(int t=1;t<=n;t++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(map[i][t]!=INFINITY&&map[t][j]!=INFINITY&&map[i][j]>map[i][t]+map[t][j]){
map[i][j]=map[i][t]+map[t][j];
path[i][j]=t;
}
}
}
}
}
int main(){
int x,y,w;
cin>>n>>m;
Init();
for(int i=1;i<=m;i++){
cin>>x>>y>>w;
map[x][y]=map[y][x]=w;
path[x][y]=x;
}
Floyd();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
printf("%d%c",map[i][j],j==n?'\n':' ');
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
printf("%d%c",path[i][j],j==n?'\n':' ');
}
}
cin>>x>>y;//起始
PrintPath(x,y);
return 0;
}

//无向图 全是正的正常,有负的就乱套:数不一样,有负的/负圈能打印出来,但不符合
#include <stdio.h>
#include <stdlib.h>
#define max 1000000000
int d[1000][1000],path[1000][1000];
int main(){
int i,j,k,m,n;
int x,y,z;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
d[i][j]=max;
path[i][j]=j;
}
for(i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
d[x][y]=d[y][x]=z;
}
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
if(d[i][k]+d[k][j]<d[i][j]){
d[i][j]=d[i][k]+d[k][j];
path[i][j]=path[i][k];
}
}

for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
printf("%d%c",d[i][j],j==n?'\n':' ');
int f,en;
scanf("%d%d",&f,&en);
do{
printf("%d->",f);
f=path[f][en];
}while(f!=en);
printf("%d\n",en);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: