AcWing 343. 排序 【传递闭包】【floyd】【隐藏边】【floyd的 d[][]数组的妙用】

1.首先,回忆之前学的,acwing 1125牛的旅行

可以发现floyd的核心数组        d[ i ][ j ] 本来表示的是 i 和 j 点的距离

但是可以直观明了地表示两个点之间联不联通

如果d[i][j]>inf/2,是很明显两个联通块是不连通的

2.那么此处的隐藏边,是点与点之间的关系,比如A<B 的 "<" 这层的关系 。

d[i][j]数组可以很明了得表达,任意两点之间的关系

所以floyd的d[][]数组真的炒鸡好用。

在本题中,d[][]数组开成 bool 型,可以更好表达 ,两个点之间是否存在关系

 所以,floyd 的 d[ i ][ j ]  数组真的太好用了~

------------------------------------------------------------------------------------------------------------------------- 

现在来到什么是传递闭包? 

简单来说就是关系的传递

Q1: 怎么判断一堆元素的关系没有传递性?

Ans1:找矛盾。

            1. 元素自己和自己本身不可能产生某种关系  d[i][i]==true 就意味着矛盾

            2. 枚举每一对(两两一对)元素 i,j  之间的关系,如果存在 ! d[i][j] && !d[j][i]

                 就意味着某一对元素之间一点关系都没有       

                 这样就意味着  这一堆元素不可能形成一整段的传递关系

             

343. 排序​​​​​​

给定 nn 个变量和 mm 个不等式。其中 nn 小于等于 2626,变量分别用前 nn 的大写英文字母表示。

不等式之间具有传递性,即若 A>BA>B 且 B>CB>C,则 A>CA>C。

请从前往后遍历每对关系,每次遍历时判断:

  • 如果能够确定全部关系且无矛盾,则结束循环,输出确定的次序;
  • 如果发生矛盾,则结束循环,输出有矛盾;
  • 如果循环结束时没有发生上述两种情况,则输出无定解。

输入格式

输入包含多组测试数据。

每组测试数据,第一行包含两个整数 nn 和 mm。

接下来 mm 行,每行包含一个不等式,不等式全部为小于关系。

当输入一行 0 0 时,表示输入终止。

输出格式

每组数据输出一个占一行的结果。

结果可能为下列三种之一:

  1. 如果可以确定两两之间的关系,则输出 "Sorted sequence determined after t relations: yyy...y.",其中't'指迭代次数,'yyy...y'是指升序排列的所有变量。
  2. 如果有矛盾,则输出: "Inconsistency found after t relations.",其中't'指迭代次数。
  3. 如果没有矛盾,且不能确定两两之间的关系,则输出 "Sorted sequence cannot be determined."

数据范围

2≤n≤262≤n≤26,变量只可能为大写字母 A∼ZA∼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.

 

 

 

//传递闭包普通版 O(m*n^3)

#include <bits/stdc++.h>
using namespace std;
const int N=26;  //只有26个变量,所以开到26
int n,m;

/*
注意都是布尔型,所以加减乘除也对应换成了
位运算符
*/

bool g[N][N];  //用g来表示边
bool d[N][N];  //用d来表示传递闭包
bool st[N]; //表示当前变量有没有被输出

void floyd()
{
    memcpy(d,g,sizeof d);  //d是传递闭包
    
    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];      //与&&只要有0就会出0
    }
}

int check()
{
    for(int i=0;i<n;i++)
    {
        if(d[i][i])  //如果存在自己小于自己就矛盾了
        {
            return 2; //返回矛盾类型2
        }
    }
    
    for(int i=0;i<n;i++)   //两两握手的关系
    for(int j=0;j<i;j++)
    {
        if(!d[i][j]&&!d[j][i])  //如果i,j之间一点关系都没有
        return 0; //返回矛盾类型0
    }
    
    return 1;   //没有矛盾,可传递
}

char get_min()
{
    for(int i=0;i<n;i++)  //我们要找到一个i使得它是还未被输出中的最小的
    {
        //也就是说我们要找的i不能有j还比它小
        if(!st[i])
        {
            bool flag=true;
            for(int j=0;j<n;j++)
            {
                if(!st[j]&&d[j][i]) //如果j没被输出过,并且 j表示的值<i表示的值
                {
                    flag=false;
                    break;  
                }
            }
            
            if(flag) 
            {
                st[i]=true;  //输出了,置为true
                return  'A'+i;    
            }
        }
    }
}



int main()
{
    while(cin>>n>>m,n||m)
    {
        memset(g,0,sizeof g);  //清空所有边
        int type=0; //记录最终答案的类型,0表示不确定,1表示唯一确定
        int t; //表示每一个结果对应的轮
        
        for(int i=1;i<=m;i++)  //迭代m次
        {
            char str[5];
            cin>>str;
            int a=str[0]-'A',b=str[2]-'A';
            
            if(!type)  //如果最终的结果不确定
            {
                g[a][b]=1; //建边,直到结果能确定就不用建了
                
                floyd(); //进行floyd
                type=check(); //检查结果是否能够确定
                
                
                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 
        {
            memset(st,0,sizeof st);
            //如果可以确定两两之间的关系
            printf("Sorted sequence determined after %d relations: ",t);
            for(int i=0;i<n;i++)
            printf("%c",get_min());  //从小到大输出
            printf(".\n");
        }
    }
    
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值