FYN 算法学习1~

FLOYD算法求最小环及路径输出

两道模板题

1.http://acm.hdu.edu.cn/showproblem.php?pid=1599 这是求最小环的模板题
2.http://poj.org/problem?id=1734 这是输出路径的模板题
由于都是模板题,题意就不再赘述,直接从算法讲起~

FLOYD算法

FLOYD算法是通过类似动态规划的方法求解最短路径问题的高效算法,对于正权值和负权值(不含负环)都有效.该算法主要分为两步:第一步初始化,对于从u到v的边,用邻接矩阵mp[u][v]存储路径的权值,若无这条边则为无穷大(实际写时定成比较大的数即可),第二步状态转移,对于每一对点u,v,枚举是否有点w使得u->w->v的最短路径比u->v的最短路径小,如果是则更新它.
核心的状态转移代码如下:

mp[i][j] = min( mp[i][j], mp[i][k]+mp[k][j] );

求最小环

FLOYD法已求得了到最外层循环k时,所有点对间以点1,2,……,k-1为中间点的最短路径.对于每一个环,这个环可以看为最大编号的点C与其相邻的两个点 A 和B 与 A 到 B 的最短路上的点.因此可以用floyd法拓展.
下面是完整代码:

#include<iostream>
using namespace std;
typedef long long int ll;
const ll inf=1e9;
const ll MAXN=110;
ll mp[MAXN][MAXN],dis[MAXN][MAXN];
ll n,m,u,v,len,mincost,temp,num,s;
void init() {
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            mp[i][j]=inf;
            dis[i][j]=inf;
        }
    }
    for(int i=1; i<=m; i++) {
        cin>>u>>v>>len;
        mp[u][v]=mp[v][u]=dis[u][v]=dis[v][u]=min(mp[u][v],len);
    }
}
void floyd() {
    mincost=inf;
    for(int k=1; k<=n; k++) {
        for(int i=1; i<k; i++) {
            for(int j=i+1; j<k; j++) {
                temp=dis[i][j]+mp[i][k]+mp[k][j];
                if(temp<mincost) {
                    mincost=temp;
                }
            }
        }
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=n; j++) {
                temp=dis[i][k]+dis[k][j];
                if(dis[i][j]>temp) {
                    dis[i][j]=temp;
                }
            }
        }
    }
}
int main() {
    while(cin>>n>>m) {
        init();
        floyd();
        if(mincost==inf) cout<<"It's impossible."<<endl;
        else cout<<mincost<<endl;
    }
    return 0;
}

输出最小环路径

我们用一个road[]数组存储输出的最小路径,在每次更新最小环的值时更新这一数组,从开始的点s不断向前推即可.

cnt=0;
s=j;
while(s!=i) {
    road[cnt++]=s;
    s=p[i][s];
}
road[cnt++]=i;
road[cnt++]=k;

这就是最小环路径的记录部分,注意p[][]数组的初始化,将p[i][j]初始化为i,p[i][j]表示从i到j的路径中经过的第一个点.
下面是完整代码:

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long int ll;
const int inf=1e6;
const int MAXN=110;
int mp[MAXN][MAXN],dis[MAXN][MAXN],road[MAXN],p[MAXN][MAXN];
int n,m,u,v,len,mincost,temp,cnt,s;
void init() {
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            mp[i][j]=inf;
            dis[i][j]=inf;
            p[i][j]=i;
        }
    }
    for(int i=1; i<=m; i++) {
        scanf("%d%d%d",&u,&v,&len);
        mp[u][v]=mp[v][u]=dis[u][v]=dis[v][u]=min(mp[u][v],len);
    }
}
void floyd() {
    mincost=inf;
    for(int k=1; k<=n; k++) {
        for(int i=1; i<k; i++) {
            for(int j=i+1; j<k; j++) {
                temp=dis[i][j]+mp[i][k]+mp[k][j];
                if(temp<mincost) {
                    mincost=temp;
                    cnt=0;
                    s=j;
                    while(s!=i) {
                        road[cnt++]=s;
                        s=p[i][s];
                    }
                    road[cnt++]=i;
                    road[cnt++]=k;
                }
            }
        }
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=n; j++) {
                temp=dis[i][k]+dis[k][j];
                if(dis[i][j]>temp) {
                    dis[i][j]=temp;
                    p[i][j]=p[k][j];
                }
            }
        }
    }
}
int main() {
    scanf("%d%d",&n,&m);
    init();
    floyd();
    if(mincost>=inf) printf("No solution.");
    else {
        for(int i=0;i<cnt;i++){
            printf("%d ",road[i]);
        }
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值