您的位置:首页 > 其它

POJ 1509 循环同构的最小表示法

2015-06-11 12:42 411 查看
题目大意:

给定一个字符串,可以把一段尾部接到头部,这样找到一个最小的字符串

方案一:

利用循环同构中找最小表示的方法来解决

论文参考http://wenku.baidu.com/view/438cad13a2161479171128b6.html

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;
#define N 10005
char s
;

inline int minpos(char *s)
{
int l = strlen(s);
int i=0 , j=1 , k=0;
while(i<l&&j<l&&k<l){ //这里k<l是防止出现所有数都一样导致无限循环
if(i == j) j++;
else if(s[(i+k)%l]>s[(j+k)%l]){
i = i+k+1;
k=0;
}
else if(s[(i+k)%l]<s[(j+k)%l]){
j = j+k+1;
k=0;
}
else k++;
}
return min(i , j)+1;
}

int main()
{
// freopen("a.in" , "r" , stdin);
int T;
scanf("%d" , &T);
while(T--)
{
scanf("%s" , s);
printf("%d\n" , minpos(s));
}
return 0;
}


后缀自动机写法:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
#define M 26
#define N 40100
char str
;

struct SamNode{
SamNode *son[M] , *f;
int l , s;
};

struct Sam{
SamNode sam
, *root , *last;
int cnt;

void init(){
cnt = 0;
memset(sam , 0 , sizeof(sam));
root = last = &sam[0];
}

void add(int x){
SamNode *p = &sam[++cnt] , *jp=last;
/*
这里p->s = jp->s+1写成p->s = p->l也是一样的,因为对于每次当前的last来说,
l和s的值是一样的,因为每次当前的last都是处于字符串的位置上的
数,不是额外添加的节点
*/
p->l = jp->l+1; p->s = jp->s+1;
last = p;
for(; jp&&!jp->son[x] ; jp=jp->f) jp->son[x] = p;
if(!jp) p->f=root;
else{
if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x];
else{
SamNode *r = &sam[++cnt] , *q = jp->son[x];
*r=*q;
r->l = jp->l+1 ; r->s = p->l;
q->f = p->f = r;
for(; jp && jp->son[x]==q ; jp=jp->f) jp->son[x]=r;
}
}
}
}sam;

int solve(int len)
{
SamNode *cur = sam.root;
for(int i=0 ; i<len ; i++){
for(int j=0 ; j<26 ; j++){
if(cur->son[j]){
cur = cur->son[j];
break;
}
}
}
return cur->s-len+1;
}

int main(int argc, char *argv[]) {
//    freopen("in.txt" , "r" , stdin);
//    freopen("out.txt" , "w" , stdout);
int T;
scanf("%d" , &T);
while(T--){
scanf("%s" , str);
int len = strlen(str);
sam.init();
for(int i=0 ; i<len ; i++)
str[len+i] = str[i];
for(int i=0 ; i<len*2 ; i++)
sam.add(str[i]-'a');
int ret = solve(len);
printf("%d\n" , ret);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: