poj 1094 全排序

看discuss好多人用拓扑排序做的,思想很有启发性,可以尝试下。下面是我的解法:


/*
 *  poj 1094 全排序问题

    题目大意:
        题目给出一组两两元素间的严格弱序关系,逐对的读入各关系对,判断到目前对儿为止
        能否给出所有元素的全排序关系,或者发现了前后矛盾的关系,甚至读完所有的对儿仍无
        法确定全排序关系。

    数学模型:
        m[i, j]表示元素i与元素j相比较的大小结果: -1表示小雨,0表示相等,1表示大于

    解题思路:
        1、读入关系对a<b
        2、遍历m[a]行,寻找所有元素x<=a -- 其实只有a=a。
        3、遍历m[b]行,寻找所有元素y>=b。
        4、针对每对(a,b)更新m[a,b]和m[b,a]。更新的同时检查m[a,b]的值:
            4.1、如果m[a,b]==1表示发现矛盾对,结束本测试例的处理,输出矛盾。
            4.2、如果没发现矛盾,则检查是否所有m的元素都有了合法值?
                 如果是表示全序关系已经可以确定,结束查找,根据该m表各值排序各元素即可。
                 如果不是返回第3步,继续。

    注意事项:
        1、本题第4.2步中,即使检测到所有m的元素均有非法值了,仍然要执行完该关系对的处理。
           因为该关系对引发的直接或者连锁关系中可能会有矛盾存在。见文件底部测试例9
        
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

namespace {
    using namespace std;

    const int N_MAX = 26;
    
    int matrix[N_MAX][N_MAX]; // 关系记录矩阵
    
    char sequence[N_MAX]; // 待排序元素记录

    // 元素比较函数
    int object_cmp(const void *pOP1, const void *pOP2)
    {
        char *pCh1 = (char *)pOP1;
        char *pCh2 = (char *)pOP2;

        return matrix[*pCh1-'A'][*pCh2-'A'];
    }
}

int main()
{
    int n, m;
    
    while (scanf("%d %d", &n, &m))
    {
        if (n==0 || m==0)
        {
            break;
        }

        // 状态初始化
        for (int i=0; i<n; i++)
        {
            sequence[i] = 'A'+i;
        }
        memset(matrix, 0, sizeof(matrix));

        // 算法核心部分
        int  nLeft = n*n - n;        // matrix中待决定的关系对数
        int  nCurRelation = 0;       // 当前处理的关系对序数,当能决定个元素的全序后,该计数停止增长
        bool bInconsistency = false; // 矛盾标志
        
        char relation[8]; // 关系字符串存储
        int xi, yi;       // a和b的编号
        for (int k=0; k<m; k++)
        {
            scanf("%s", relation); // 持续读入,即使已经有答案了也要执行,否则影响下一测试例
            xi = relation[0] - 'A';
            yi = relation[2] - 'A';

            if (!bInconsistency && nLeft>0)
            {
                nCurRelation++;
            }
            
            for (int j1=0; j1<n && !bInconsistency && nLeft>=0; j1++)
            {
                if (matrix[xi][j1]!=1 && j1!=xi) continue; // 查找x<=a
                
                for (int j2=0; j2<n && !bInconsistency && nLeft>=0; j2++)
                {
                    if (matrix[yi][j2]!=-1 && j2!=yi) continue; // 查找y>=b

                    if (matrix[j1][j2] == 1) // 检查矛盾
                    {
                        bInconsistency = true;
                        continue;
                    }

                    if (matrix[j1][j2] == -1) continue; // 如果该关系已被处理过,不再处理
                    
                    matrix[j1][j2] = -1; // 置m[x][y]和m[y][x]
                    matrix[j2][j1] = 1;
                    
                    nLeft -= 2; // 待定关系对减2
                }
            }
        }

        if (bInconsistency) // 优先检查矛盾与否
        {
            printf("Inconsistency found after %d relations.\n", nCurRelation);
        }
        else if (nLeft>0) // 检查是否可以决定全序
        {
            printf("Sorted sequence cannot be determined.\n");
        }
        else
        {
            sequence[n] = '\0';
            qsort(sequence, n, sizeof(char), object_cmp); // 排序
            printf("Sorted sequence determined after %d relations: %s.\n", nCurRelation, sequence);
        }
    }
    return 0;
}

/*
    poj 测试数据9

    10 40
    E<J
    C<A
    G<J
    C<H
    G<I
    A<I
    D<I
    D<A
    G<E
    F<I
    A<J
    D<H
    E<B
    A<B
    D<E
    E<I
    D<C
    C<G
    F<A
    F<H
    D<B
    I<J
    I<B
    F<C
    J<B
    D<F
    G<H
    A<H
    I<H
    A<E
    E<H
    F<J
    H<B
    G<A
    G<F
    D<G
    F<E
    F<B
    C<B
    C<I
    0 0

    我就是这组数据错了,导致第一次提交WA,本数据的正确结果应该是:

    Inconsistency found after 35 relations.

    但是我一开始的结果却是:

    Sorted sequence determined after 35 relations: DFCGAEIHJB.

    该结果显然与第35组关系对G<F矛盾。之所以产生这样的矛盾,就在于
    原程序在处理该关系时,优先处理该关系引起的传递关系,导致nLeft
    减为0,之后不再处理引起的其他反应--包括该关系对本身。

    修改很简单,把原来判断nLeft>0的地方改成nLeft>=0即可。


*/



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值