1. 程式人生 > >hdu 2609 How many (最小表示法)

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;
}