Loading

floyd算法

应用

  • 求多源点最短路
  • 传递闭包
  • 找最小环(对于正权图而言)
  • 恰好经过k条边的最短路

floyd算法原理

算法模板

//初始化:d[i][i] = 0 且不相连的节点距离需要初始化为INF
for(int k = 0; k < n; k++)
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            d[i][j] = min(d[i][j] , d[i][k] + d[k][j]);

空间优化

  • 需要说明表达式d[k][i][j] = min(d[k][i][j] , d[k-1][i][k] + d[k-1][k][j])d[i][j] = min(d[i][j] , d[i][k] + d[k][j])等价
  • d[k-1][i][k] <=> d[i][k]为例,只需要说明每一次d[i][k]的值可能被更新时,d[i][k]的值不变
  • j=k, 则d[k][i][k] = min(d[k][i][k] , d[k-1][i][k] + d[k-1][k][k]).因为d[k-1][k][k]=0,所以d[i][k]的值不会发生改变,总是第k-1层的值

例题-牛的旅行

题目链接

题解

1.根据输入建立邻接矩阵d,跑一边floyd算法
2.求每一个连通块的直径(距离最远的两点的距离),答案必定>=每一连通块的直径
3.枚举连接两个连通块内的某点所形成的新连通块的直径中的最小值,答案必定>=这个最小值
4.新的连通块直径(例如连接i,j两点):maxd[i] + dist(i , j) + maxd[j]

代码

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 160;
const double INF = 1e20;
#define x first
#define y second
typedef pair<int ,int> PII;
PII p[N];
double d[N][N] , maxd[N];
char g[N][N];
int n;

double get_dist(PII a , PII b)
{
    double x = a.x - b.x , y = a.y - b.y;
    return sqrt(x*x + y*y);
}

int main()
{
    cin >> n;
    for(int i = 0; i < n; i++)  cin >> p[i].x >> p[i].y;

    for(int i = 0; i < n; i++)  cin >> g[i];

    //初始化距离
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            if(i != j)
            {
                if(g[i][j] == '1') d[i][j] = get_dist(p[i] , p[j]);
                else d[i][j] = INF;
            }

    //Floyd算法
    for(int k = 0; k < n; k++)
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                d[i][j] = min(d[i][j] , d[i][k] + d[k][j]);

    //求连通块内的直径
    for(int i = 0; i < n; i++)
        for(int j = 0;j < n; j++)
            if(d[i][j] < INF)
                maxd[i] = max(maxd[i] , d[i][j]);

    //情况1:结果必然 >= 每一连通块的直径
    double ans = 0;
    for(int i = 0; i < n; i++)  ans = max(ans , maxd[i]);

    //情况2:结果必然 >= 连接一条边后新的连通块的直径(枚举最小值)
    double res = INF;
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            if(d[i][j] >= INF)
                res = min(res , maxd[i] + get_dist(p[i] , p[j]) + maxd[j]);

    printf("%lf\n" , max(ans , res));

    return 0;
}

例题-排序(传递闭包)

floyd算法求传递闭包

  • 1.邻接矩阵初始化d[i][j]:1-表示i,j之间存在i到j的单向路径 0-表示不存在路径
  • 2.将转移关系修改为:d[i][j] = d[i][j] | ( d[i][k] & d[k][j] ) -(表示 i->k , k->j两段路径都存在)
  • 3.整体认识:在算法结束后,所有的间接关系,例如 i->j , j->k,会直接表示出来,即d[i][k] = 1

题解

  • 在本题中可以将A < B类比成A->B
  • 则存在矛盾例如A<B , B<C , C<A , 可以推知A<A , 即A->A , d[i][i] = 1
  • 变量A,B不存在相对关系:d[a][b] = 0 && d[b][a] = 0

代码

#include <iostream>
#include <cstring>
using namespace std;
const int N = 30;
int d[N][N] , g[N][N];
int n , m;

void floyd()
{
    memcpy(d , g , sizeof g);

    for(int k = 0; k < n; k++)
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j ++)
                d[i][j] |= d[i][k] & d[k][j];
}

int check()
{
    for(int i = 0; i < n; i++)
        if(d[i][i]) return 2;

    for(int i = 0; i < n; i++)
        for(int j = i + 1; j < n; j++)
            if(!d[i][j] && !d[j][i])  return 0;

    return 1;
}

char get_min(int val)
{
    for(int i = 0; i < n; i++)
    {
        int cnt = 0;
        for(int j = 0; j < n; j++)
            if(d[i][j]) cnt++;
        if(cnt == val) return i + 'A';
    }
}

int main()
{
    while(cin >> n >> m , n || m)
    {
        char str[4];
        //type: 0-表示存在无法判断的关系  1-表示所有关系已确定   2-关系存在矛盾
        int type = 0 , t;

        memset(g , 0 , sizeof g);
        for(int i = 1; i <= m; i++)
        {
            cin >> str;
            int a = str[0] - 'A' , b = str[2] - 'A';

            if(!type)
            {
                g[a][b] = 1;
                floyd();
                type = check();
                if(type) t = i;
            }
        }    
            if(!type) printf("Sorted sequence cannot be determined.\n");
            else if(type == 2)  printf("Inconsistency found after %d relations.\n" , t);
            else
            {
                printf("Sorted sequence determined after %d relations: " , t);
                for(int i = 0; i < n; i++)
                    printf("%c" , get_min(n - i - 1));
                puts(".");
            }
    }

    return 0;
}

参考文献

Acwing-算法提高课-图论章节
https://www.acwing.com/activity/content/introduction/16/

posted @ 2020-12-22 19:41  Krocz  阅读(101)  评论(0编辑  收藏  举报