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;
}

猜你喜欢

转载自blog.csdn.net/Raymond_YP/article/details/109789802
今日推荐