最小表示法

为什么要写这个算法?
看了看NOIP考点 这好像是省选的知识点诶
我作为一个今年11月份考完NOIP就AFO的OIer,我看这干啥?
我们还是要把目标放长远一点,我也不敢打包票,我一生中不会遇到这个算法。
对吧?
而且,还能提高自己的信息学素养!多好。
那么这个方法是怎么来的呢?
我做一道题(下面会粘的练习题)时,发现了这个算法,去网上找博客,但是那个人讲得很迷,另一个人又讲得很长,我一想,这一定是一个很简单的算法,算了,我自己写吧!
于是就得到了接下来的这个方法,当然已经经过测试,没有问题。
那么,下面我们步入正题。

什么是最小表示法?

我们的对象是字符串(读者:???你不要胡说,我有女朋友的好吧!你对象才是字符串嘞!)
我们这里的字符串不是一般的字符串,而是可以进行轮换对称变换的字符串。
也就是说我们把”abcd”、”bcda”、”cdab”、”dabc”视为一个字符串。
那么对于一个这样的字符串,它的所有的形式的集合中,字典序最小的一个就是该字符串的最小表示法。
比如上面的那一个,最小表示法就是”abcd”

原理

我们知道,越靠左边的字符对字典序的影响越大
所以我们肯定优先考虑最左边的一个字符
我们又由轮换对称变换的定义,可以知道,我们一旦确定一个字符串的起始位置,整个字符串的形式就确定了。
所以我们的目标就求这个其实位置。
所以我们设置两个下标i和j
i=0,j=1
然后我们有一个字符串c
我们开始比较i位和j位的字符
如果c[i]<c[j]
那么很好,显然i不变,j++即可
如果c[i]>c[j]
那么j位显然比i位更优,所以让i=j,然后j++
下面就是重点了
如果c[i]==c[j]
怎么办呢?
(读者:那就判断他们各自后面一位呗!)
没错就是这样
我们再设置一个变量k
让它从1开始递增到n-1即可(再往下就重复了)
下面我们需要了解一个性质:

用k比较过的位置就不需要再把他们作为头进行比较了

这个自己体会一下,我这里不提供证明。(其实分类讨论一下即可)

代码

int getmin(char* c){
    int n=strlen(c);
    int i=0,k=0;
    int j=1;
    while(i<n&&j<n){
        if(c[i]<c[j]){
            j++;
        }else if(c[i]>c[j]){
            i=j++;
        }else{
            int fir=1;
            for(k=1;k<n;k++){
                if(c[(i+k)%n]<c[(j+k)%n]){
                    j=(j+k+1);fir=0;
                    break; 
                }else if(c[(i+k)%n]>c[(j+k)%n]){
                    i=j;fir=0;
                    j=(j+k+1);
                    break;
                }
            }
            if(fir){
                break;
            }
        }
    }
    return min(i,j);
}

练习题

bzoj1398 寻找主人

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值