hdu 2609 字符串最小表法

57 篇文章 0 订阅
2 篇文章 0 订阅

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=2609

最小表示法:

循环字符串的最小表示法的问题可以这样描述:

对于一个字符串S,求S的循环的同构字符串S’中字典序最小的一个。

由于语言能力有限,还是用实际例子来解释比较容易:

设S=bcad,且S’是S的循环同构的串。S’可以是bcad或者cadb,adbc,dbca。而且最小表示的S’是adbc。

对于字符串循环同构的最小表示法,其问题实质是求S串的一个位置,从这个位置开始循环输出S,得到的S’字典序最小。

一种朴素的方法是设计i,j两个指针。其中i指向最小表示的位置,j作为比较指针。

令i=0,j=1

如果S[i] > S[j] i=j, j=i+1

如果S[i] < S[j] j++

如果S[i]==S[j] 设指针k,分别从i和j位置向下比较,直到S[i] != S[j]
         如果S[i+k] > S[j+k] i=j,j=i+1

         否则j++
返回i

起初,我想在j指针后移的过程中加入一个优化。就是j每次不是加1,而是移动到l位置。其中,l>j且S[l]<=S[j]。但是,即使加入这一优化,在遇到bbb…bbbbbba这样的字符串时复杂度将退化到O(n^2)。

注意到,朴素算法的缺陷在于斜体的情况下i指针的移动太少了。针对这一问题改进就得到了最小表示法的算法。最小表示法的算法

思路是维护两个指针i,j。

令i=0,j=1

如果S[i] > S[j] i=j, j=i+1

如果S[i] < S[j] j++

如果S[i]==S[j] 设指针k,分别从i和j位置向下比较,直到S[i] != S[j]

         如果S[i+k] > S[j+k] i=i+k

         否则j++

返回i和j的小者

注意到上面两个算法唯一的区别是粗体的一行。这一行就把复杂度降到O(n)了。
 

题目 

How many

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4536    Accepted Submission(s): 2078


 

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

 

 

Author

yifenfei

 

 

Source

奋斗的年代

 

 

Recommend

yifenfei

解题思路:

题目大意:

有n个有01组成的字符串,每个字符串都代表一个项链,那么该字符串就是一个环状的结构,求可以经过循环旋转,最后不同的串有多少个。。

算法思想:

将每个字符串转换成最小串,然后放在set里面去重。

 This is the code:

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<sstream>
#include<stack>
#include<string>
#include<set>
#include<vector>
using namespace std;
#define PI acos(-1.0)
#define pppp cout<<endl;
#define EPS 1e-8
#define LL long long
#define ULL unsigned long long     //1844674407370955161
#define INT_INF 0x3f3f3f3f      //1061109567
#define LL_INF 0x3f3f3f3f3f3f3f3f //4557430888798830399
// ios::sync_with_stdio(false);
// 那么cin, 就不能跟C的 scanf,sscanf, getchar, fgets之类的一起使用了。
const int dr[]= {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[]= {-1, 1, 0, 0, -1, 1, -1, 1};
int read()//输入外挂
{
    int ret=0, flag=0;
    char ch;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        ret = ch - '0';
    while((ch=getchar())>='0'&&ch<='9')
        ret=ret*10+(ch-'0');
    return flag ? -ret : ret;
}
const int maxn=105;
char str[maxn];
char s[maxn];

int MaxmumRepresentation(char *str)   //最大表示法
{
    int len=strlen(str);
    int i=0,j=1,k=0;
    while(i<len && j<len && k<len)
    {
        int tem=str[(i+k)%len]-str[(j+k)%len];
        if(tem==0)
            k++;
        else
        {
            if(tem>0)
                j=j+k+1;
            else
                i=i+k+1;
            if(i==j)
                j++;
            k=0;
        }
    }
    return i<j?i:j;
}

int MinmumRepresentation(char *str)   //最小表示法
{
    int len=strlen(str);
    int i=0,j=1,k=0;
    while(i<len && j<len && k<len)
    {
        int tem=str[(i+k)%len]-str[(j+k)%len];
        if(tem==0)
            k++;
        else
        {
            if(tem>0)
                i=i+k+1;
            else
                j=j+k+1;
            if(i==j)
                j++;
            k=0;
        }
    }
    return i<j?i:j;
}
set<string > ss;
int main()
{
    //freopen("D:\\chnegxubianji\\inORout\\in.txt", "r", stdin);
    //freopen("D:\\chnegxubianji\\inORout\\out.txt", "w", stdout);
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=0;i<n;++i)
        {
            scanf(" %s",str);
            int len=strlen(str);
            int t=MinmumRepresentation(str);//寻找最小起始点
            for(int j=0;j<len;j++)
                s[j]=str[(t+j)%len];
            s[len]='\0';
            ss.insert(s);
        }
        printf("%d\n",ss.size());
        ss.clear();
    }
    return 0;
}

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值