排序(Floyd求闭包)

题目描述

给定 n 个变量和 m 个不等式。其中 n 小于等于26,变量分别用前 n 的大写英文字母表示。
不等式之间具有传递性,即若 A>B 且 B>C ,则 A>C。
请从前往后遍历每对关系,每次遍历时判断:
如果能够确定全部关系且无矛盾,则结束循环,输出确定的次序;
如果发生矛盾,则结束循环,输出有矛盾;
如果循环结束时没有发生上述两种情况,则输出无定解。

输入格式

输入包含多组测试数据。
每组测试数据,第一行包含两个整数n和m。
接下来m行,每行包含一个不等式,不等式全部为小于关系。
当输入一行0 0时,表示输入终止。

输出格式

每组数据输出一个占一行的结果。
结果可能为下列三种之一:
如果可以确定两两之间的关系,则输出 “Sorted sequence determined after t relations: yyy…y.”,其中’t’指迭代次数,'yyy…y’是指升序排列的所有变量。
如果有矛盾,则输出: “Inconsistency found after t relations.”,其中’t’指迭代次数。
如果没有矛盾,且不能确定两两之间的关系,则输出 “Sorted sequence cannot be determined.”。

数据范围

2≤n≤26,变量只可能为大写字母A~Z。

输入样例1
4 6
A<B
A<C
B<C
C<D
B<D
A<B
3 2
A<B
B<A
26 1
A<Z
0 0
输出样例1
Sorted sequence determined after 4 relations: ABCD.
Inconsistency found after 2 relations.
Sorted sequence cannot be determined.
输入样例2
6 6
A<F
B<D
C<E
F<D
D<E
E<F
0 0
输出样例2
Inconsistency found after 6 relations.
输入样例3
5 5
A<B
B<C
C<D
D<E
E<A
0 0
输出样例3
Sorted sequence determined after 4 relations: ABCDE.

题目分析

这个题的第一个难点就是如何建图:即如果将这些不等式关系转化为一个图。这道题的数据范围很小,因此我们可以用邻接矩阵来存图:g[u][v]=1 //表示u<v.
解题流程为:每添加一对关系,就用Floyd处理一次,查看当前的情况:

  1. 当用题中的关系推出了a<a(即g[a][a]=1)时,就可以说明这些关系发生了矛盾
  2. 如果所有的关系都用上之后,用Floyd算法处理后,还存在一组边g[i][j]=g[j][i]=0的话,说明无法确定全部的关系,即为无解。
  3. 如果在用到第i组关系时,没有推出矛盾,且对于任意一对点都能求出相应的关系,那么根据题目要求结束循环,并输出所有的次序关系。

因为这个题的数据范围非常的小,因此我们可以用暴力求解。即每次找出当前最小值进行输出,并标记该点。

代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#define LL long long
#define ULL unsigned long long
#define PII pair<int,int>
#define x first
#define y second
using namespace std;
const int N=27,INF=0x3f3f3f3f;
bool g[N][N],d[N][N];		//g[][]记录初始的图,d[][]记录Floyd处理过的图
bool st[N];
void floyd(int n)			//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(int n)		//判断当前条件的情况
{
    
    
    for(int i=0;i<n;i++)		//如果推出了矛盾,则返回2
        if(d[i][i]) return 2;
    
    for(int i=0;i<n;i++)		//如不能完全的确定关系,那么返回0
        for(int j=0;j<i;j++)
            if(!d[i][j]&&!d[j][i]) return 0;
            
    return 1;
}
void print(int n)			//输出次序
{
    
    
    memset(st,0,sizeof st);
    for(int t=0;t<n;t++)	//循环n次,每次找出最小值并输出
    {
    
    
        for(int i=0;i<n;i++)	//枚举点
        {
    
    
            if(st[i]) continue;		//如果该点已被用过则跳过
            bool flag=true;
            for(int j=0;j<n;j++)	//枚举所有点,看看是否有比i还小的
                if(!st[j]&&d[j][i])
                {
    
    
                    flag=false;
                    break;
                }
            
            if(flag)		//如果没有则输出i
            {
    
    
                printf("%c",i+'A');
                st[i]=true;
                break;
            }
        }
    }
}
int main()
{
    
    
    int n,m;
    while(scanf("%d %d",&n,&m),n||m)
    {
    
    
        memset(g,0,sizeof g);
        char s[5];
        int type=0,t;
        for(int i=1;i<=m;i++)
        {
    
    
            scanf("%s",s);
            int a=s[0]-'A',b=s[2]-'A';
            if(!type)	//type不为0,说明已经推出了矛盾或者确定了所有关系。则不需要继续往后计算了
            {
    
    
                g[a][b]=1;			//加边
                floyd(n);			//求闭包
                type=check(n);		//判断加入该边之后的情况
                if(type) t=i;		//如果已经推出了矛盾或者确定了所有关系,那么记录当前位置
            }
        }
        //输出结果
        if(!type) puts("Sorted sequence cannot be determined.");
        else if(type==2) printf("Inconsistency found after %d relations.\n",t);
        else {
    
    
            printf("Sorted sequence determined after %d relations: ",t);
            print(n);
            puts(".");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/li_wen_zhuo/article/details/109660239