POJ题解Sorting It All Out-传递丢包+倍增

  • 题目链接:

    http://poj.org/problem?id=1094

  • 题目大意(直接从谷歌翻译上复制下来的):

    • 描述

      不同值的递增排序顺序是其中使用某种形式的小于运算符来将元素从最小到最大排序的顺序。例如,排序后的序列A,B,C,D意味着A <B,B <C和C <D.在这个问题中,我们将给出一组形式A <B的关系并要求你确定是否已排序的订单已被指定。

    • 输入

      输入由多个问题实例组成。每个实例都以包含两个正整数n和m的行开始。第一个值表示要排序的对象数量,其中2 <= n <= 26.要排序的对象将是大写字母的前n个字符。第二个值m表示将在此问题实例中给出的形式A <B的关系数目。接下来是m行,每行包含一个由三个字符组成的关系:大写字母,字符“<”和第二个大写字母。没有字母会超出字母表前n个字母的范围。 n = m = 0的值表示输入结束。

    • 输出

      对于每个问题实例,输出由一行组成。这条线应该是以下三条中的一条:

      xxx关系后确定的排序顺序:yyy ... y。
      分类序列无法确定。
      xxx关系后发现不一致。

      其中xxx是在确定排序序列或发现不一致时的处理关系数,以先到者为准,yyy ... y是已排序的递增序列。

  • 分析:

    很明显一道传递丢包的变式,怎么处理这些恼人的输出呢?虽然《算法竞赛进阶指南》说用二分,但我个人认为用倍增更好。

    首先我们用\(f[x][y]\)表示\(x>y\)的关系,然后使用倍增。

    \(check()==1\)时说明可以判断出关系,缩短倍增长度

    \(check()==2\)时说明矛盾,同样缩短长度

    \(check()==0\)时说明判断不了全部关系,增大长度

    首先如果\(check(m)==0\)说明Sorted sequence cannot be determined.

    然后按照常规思维写就好了

    如果不知道常规思维怎么写就看我另一篇关于传递丢包的博客吧

  • 吐槽:

    • 辣鸡Dev Cpp

      玄学原因一直过不了样例,最后在在线IDE上一遍就过了,害我调了那么久。

    • 最近文化课压力大,好久没做OI题,感觉手感思维都有些生疏,码风比较乱。数学圆锥曲线毁我青春,作业真难做

  • 代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <cstring>
using namespace std;
const int maxn=29;
int f[maxn][maxn];
int ans[maxn];
int N,n,m;
struct Relation{
    int x,y;
    bool bigger;
}rel[19260817];
char tmp[15];
int check(int len){
    memset(ans,0,sizeof(ans));
    memset(f,0,sizeof(f));
    for(register int i=1;i<=len;i++){
        if(rel[i].bigger){
            f[rel[i].x][rel[i].y]=1;
        }
        else{
            f[rel[i].y][rel[i].x]=1;
        }
    }
/*  for(register int i=0;i<n;i++){
        for(register int j=0;j<n;j++)printf("%d",f[i][j]);
        puts("");
    }*/
    for(register int k=0;k<n;k++){
        for(register int i=0;i<n;i++){
            for(register int j=0;j<n;j++){
                if(i==j)continue;
                f[i][j]|=f[i][k]&f[k][j];
            }
        }
    }
    int res=1;
    for(register int i=0;i<n;i++){
        int cnt=0;
        for(register int j=0;j<n;j++){
            if(i==j)continue;
            if(f[i][j]&&!f[j][i]){
                cnt++;
            }
            else if(f[i][j]&&f[j][i]){
                res=2;//return 2;
            }   
            else if(!f[i][j]&&!f[j][i]){
                if(res!=2)res=0;//return 0;
            }
        }
        if(res==2)return 2;
        ans[cnt+1]=i;
    }
    return res;
}
int main(){
    while(scanf("%d %d",&n,&m)!=EOF&&(n||m)){
        for(register int i=1;i<=m;i++){
            scanf("%s",tmp);
            int x=tmp[0]-'A',y=tmp[2]-'A';
            rel[i].x=x,rel[i].y=y;
            if(tmp[1]=='>'){
                rel[i].bigger=1;
            }
            else rel[i].bigger=0;
        }
        if(!check(m)){
           puts("Sorted sequence cannot be determined.");
           continue;
        }
        int k=0,p=1,flag;
        while(p!=0){
            flag=check(k+p);
            if(!flag){
                k+=p;
                p=p<<1;
            }
            else{
                p=p>>1;
            }
            while(k+p>m)p=p>>1;
        }
        k++;
        if(flag==1){//
           printf("Sorted sequence determined after %d relations: ",k);
           for(register int i=1;i<=n;i++){printf("%c",ans[i]+'A');}
           puts(".");
        }
        else if(flag==2){//mao dun
           printf("Inconsistency found after %d relations.\n",k);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Rye-Catcher/p/9145597.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值