hdu 2609 How many (最小表示法)


题目:

Problem Description

Give you n ( n < 10000) necklaces ,the length of necklace will not large than 100,tell me
How many kinds of necklaces total have.(if two necklaces can equal by rotating ,we say the two necklaces are some).
For example 0110 express a necklace, you can rotate it. 0110 -> 1100 -> 1001 -> 0011->0110.

Input

The input contains multiple test cases.
Each test case include: first one integers n. (2<=n<=10000)
Next n lines follow. Each line has a equal length character string. (string only include '0','1').

Output

For each test case output a integer , how many different necklaces.

Sample Input

4 0110 1100 1001 0011 4 1010 0101 1000 0001

Sample Output

1 2


解题思路:

用最小表示法 给每个数字表示出来 存储进set里 因为set不可重复 所以只需要输出 set 的大小即可


最小表示法

参考:http://www.cnblogs.com/eternhope/p/9972846.html

最小表示法是求与某个字符串循环同构的所有字符串中,字典序最小的串是哪个。

比如说一个字符串jdrakioi,它长为8,也就是说最多有八种循环同构的方法。

jdrakioi、drakioij、rakioijd、akioijdr、kioijdra、ioijdrak、oijdraki、ijdrakio。

这几个串在原串上的开始位置分别是0,1,2,3,4,5,6,7。

设i、j是两个“怀疑是最小的位置”,比如说如果你比较到了jdrakioi的两个i,你目前还不知道从哪个i开始的字符串是最小的。

设k表示,从i往后数和从j往后数,有多少是相同的。

开始时先设i=0,j=1,k=0。

每次都对i+k、j+k进行一次比较。

发现i+k有可能大于字符串长度n啊,怎么办呢?

首先想到将字符串倍长:jdrakioijdrakioi。

但是这样做很麻烦,而且倍长之后,前后两段都是完全一样的。

所以我们只需要取模n就好了:(i+k)%n。

这么做就要求字符串从0开始,如果从1开始的话,就有点麻烦了,还得+1-1什么的,不如从0开始简单明了。

比较完i+k和j+k,如果两个字符相等,那么显然k++。

如果不相等,那么哪边比较大,哪边就肯定不是最小的了,同时把k重置为0。

如果出现了i、j重合的情况,把j往后移动一位。

最后输出i、j较小的那个就好了。

最小表示法模版代码

int getmin()
{
    int i=0,j=1,k=0,t;
    while(i<n&&j<n&&k<n)
    {
        t=s[(i+k)%n]-s[(j+k)%n];
        if(!t)k++;
        else
        {
            if(t>0)i+=k+1;
            else j+=k+1;
            if(i==j)j++;
            k=0;
        }
    }
    return i<j?i:j;
}

本题解:

//
//  main.cpp
//  2609
//
//  Created by zhan_even on 2018/11/18.
//

#include <iostream>
#include <string>
#include <set>
using namespace std;

int getmin(char s[], int n){
    int i=0,j=1,k=0,t;
    while(i < n && j < n && k < n){
        t = s[(i + k) % n] - s[(j + k) % n];
        if(!t)
            k++;
        else{
            if(t>0)
                i += k+1;
            else
                j += k+1;
            if(i == j)
                j++;
            k=0;
        }
    }
    return i<j?i:j;
}

int main(int argc, const char * argv[]) {
    int n;
    set <string> se;
    char s[100001];
    char temp[110];
    while (cin >> n) {
        se.clear();
        while (n--) {
            cin >> s;
            int len = strlen(s);
            int minlop = getmin(s ,len);
            int cnt = 0;
            for (int i = minlop ; i < len; i++) {
                temp[cnt++] = s[i];
            }
            for (int i = 0; i < minlop; i++){
                temp[cnt++] = s[i];
            }
            temp[cnt] = '\0';
            se.insert(temp);
        }
        cout << se.size() << endl;
        
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41568105/article/details/84225666
今日推荐