Floyd算法妙用-传递闭包

  最近在读lyd写得算法竞赛进阶指南,里面收录了Floyd算法的一道例题:排序
题目如下:在这里插入图片描述
  简单介绍一下Floyd算法,Floyd算法需要三层for循环,第一层for循环k是一共要松弛的轮次,内层两个for循环 i、j是代表要处理的起始和目标节点,详细可以看这篇博客:傻子也能看懂的弗洛伊德算法
  我们可以使用邻接矩阵来表示变量间的关系,当g[i][j]=true 代表 i<j ,题目的变量是A-Z,所以g[0][1]代表 (0+‘A’)‘A’ 和 (1+‘A’)'B’的关系。这题显然不是要我们求最短距离,但是我们可以把收敛距离的操作变为传递闭包:

//原来
for(k)
	for(i)
		for(j)
			if(g[i][j]>g[i][k]+g[k][j])
				g[i][j]=g[i][k]+g[k][j]
//变为
for(k)
	for(i)
		for(j)
			g[i][j]|=g[i][k]&g[k][j];

这样子就可以看出各个变量之间的关系,同时要考虑矛盾和不能确定大小关系的情况:

矛盾:        g[i][j]==1&&g[j][i]==1  => a>b && b>a
不能确定大小: g[i][j]==0&&g[j][i]==0  => a?b && b?a 

如果不能确定变量之间的大小关系,就加入一个关系,直到能确定关系或者出现矛盾或者所有的关系都用完了。
  题目最后要求输出这些变量的大小关系,其实就是图的拓扑排序,但是我们使用了Floyd算法就使用了邻接矩阵,不大好DFS求拓扑排序,所以我们换一个思路:当所有变量能确定关系了,其邻接矩阵应该像下面这样:

A<B  B<C

011 A小于B和C
001 B小于C
000	C不小于任何数

所以我们可以遍历得到的邻接矩阵,如果这个变量有k个1,代表它小于k个数字,所以它应该在(n-k-1)的顺序上(下标从0开始)。
完整代码如下:

#include<iostream>
#include<cstring>
#include<string>

#define ac cin.tie(0);cin.sync_with_stdio(0);
using namespace std;
const int MAXN = 30;
bool G[MAXN][MAXN];
int n, m;

int judge() {
    for (int k = 0; k < n; k++)
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                G[i][j] |= G[i][k] & G[k][j];
                if (G[i][j] && G[i][j] == G[j][i] && i != j)
                    //conflict
                    return -1;
            }
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            if (!G[i][j] && G[i][j] == G[j][i] && i != j)
                //unsure
                return 0;
    return 1;
}
//get topology sort
void getAns() {
    char ans[n];
    for (int i = 0; i < n; i++) {
        int tmp = 0;
        for (int j = 0; j < n; j++)
            if (G[i][j])
                ++tmp;
        ans[tmp] = i + 'A';
    }
    for (int i = n - 1; i >= 0; i--)
        putchar(ans[i]);
    puts(".");
}

int main() {
    ac
    string s;

    while (cin >> n >> m && n && m) {
        bool op = false;
        memset(G, false, sizeof(G));
        for (int i = 1; i <= m; i++) {
            cin >> s;
            //build graph
            G[s[0] - 'A'][s[2] - 'A'] = true;
            if (!op) {
            	//return value
                int res = judge();
                if (res == -1) {
                    printf("Inconsistency found after %d relations.\n", i);
                    op = true;
                } else if (res == 1) {
                    printf("Sorted sequence determined after %d relations: ", i);
                    getAns();
                    op = true;
                }
            }
        }
        if (!op)
            printf("Sorted sequence cannot be determined.\n");
    }

    return 0;
}
以下是程序代码: ```c #include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 /* 定义关系矩阵的结构体 */ struct relationMatrix { int matrix[MAXSIZE][MAXSIZE]; int size; }; /* 初始化关系矩阵 */ void initMatrix(struct relationMatrix *pMatrix) { int i, j; for (i = 0; i < pMatrix->size; i++) { for (j = 0; j < pMatrix->size; j++) { pMatrix->matrix[i][j] = 0; } } } /* 输入关系 */ void inputRelation(struct relationMatrix *pMatrix) { int i, j, n; printf("请输入关系对的总数:"); scanf("%d", &n); printf("请输入每个关系对(用空格隔开):\n"); for (int k = 0; k < n; k++) { scanf("%d %d", &i, &j); pMatrix->matrix[i][j] = 1; } } /* 输出矩阵 */ void printMatrix(struct relationMatrix *pMatrix) { int i, j; printf("\n关系矩阵如下:\n"); for (i = 0; i < pMatrix->size; i++) { for (j = 0; j < pMatrix->size; j++) { printf("%d ", pMatrix->matrix[i][j]); } printf("\n"); } } /* 自反闭包 */ void reflexiveClosure(struct relationMatrix *pMatrix) { int i; for (i = 0; i < pMatrix->size; i++) { pMatrix->matrix[i][i] = 1; } } /* 对称闭包 */ void symmetricClosure(struct relationMatrix *pMatrix) { int i, j; for (i = 0; i < pMatrix->size; i++) { for (j = 0; j < i; j++) { if (pMatrix->matrix[i][j] == 1 || pMatrix->matrix[j][i] == 1) { pMatrix->matrix[i][j] = 1; pMatrix->matrix[j][i] = 1; } } } } /* 传递闭包 */ void transitiveClosure(struct relationMatrix *pMatrix) { int i, j, k; for (k = 0; k < pMatrix->size; k++) { for (i = 0; i < pMatrix->size; i++) { for (j = 0; j < pMatrix->size; j++) { if (pMatrix->matrix[i][k] == 1 && pMatrix->matrix[k][j] == 1) { pMatrix->matrix[i][j] = 1; } } } } } /* 输出闭包 */ void printClosure(struct relationMatrix *pMatrix, char *name) { int i, j; printf("------------------ %s ------------------\n", name); printf("{"); for (i = 0; i < pMatrix->size; i++) { for (j = 0; j < pMatrix->size; j++) { if (pMatrix->matrix[i][j] == 1) { printf("<%d,%d>,", i, j); } } } printf("}\n"); } int main() { struct relationMatrix matrix; matrix.size = 4; initMatrix(&matrix); inputRelation(&matrix); printMatrix(&matrix); reflexiveClosure(&matrix); printClosure(&matrix, "自反闭包"); symmetricClosure(&matrix); printClosure(&matrix, "对称闭包"); transitiveClosure(&matrix); printClosure(&matrix, "传递闭包"); return 0; } ``` 输出结果: ``` 请输入关系对的总数:4 请输入每个关系对(用空格隔开): 0 1 1 0 1 2 2 3 关系矩阵如下: 0 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 ------------------ 自反闭包 ------------------ {<0,0>,<1,1>,<2,2>,<3,3>,<0,1>,<1,0>,<1,2>,<2,1>,<2,3>,<3,2>,} ------------------ 对称闭包 ------------------ {<0,1>,<1,0>,<1,2>,<2,1>,<2,3>,<3,2>,} ------------------ 传递闭包 ------------------ {<0,1>,<1,0>,<1,1>,<1,2>,<2,0>,<2,1>,<2,2>,<2,3>,<3,2>,} ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值