Code From http://blog.youkuaiyun.com/cclsoft/article/details/5467743:
int MinimumRepresentation(char *s, int l)
{
int i = 0, j = 1, k = 0, t;
while(i < l && j < l && k < l) {
t = s[(i + k) >= l ? i + k - l : i + k] - s[(j + k) >= l ? j + k - l : j + k];
if(!t) k++;
else{
if(t > 0) i = i + k + 1;
else j = j + k + 1;
if(i == j) ++ j;
k = 0;
}
}
return (i < j ? i : j);
}
这比ZY的PPT容易懂多了....不过那个博客的博主好像写错了,【否则j++】那里没有改过来。
另外为什么要返回i、j的最小值呢?
注意到i、j后跳的过程中是可能超出l的范围的。
那么,最小表示法的基础练习题:给出两个序列问是否同构。
code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<climits>
#define ot "%d"
#define min(a, b) ({int _ = (a), __ = (b); _ < __ ? _ : __;})
#define maxlen 8005
using namespace std;
typedef char st[maxlen];
st a, b;
int len;
void init()
{
freopen("necklace.in", "r", stdin);
freopen("necklace.out", "w", stdout);
scanf("%s\n", a);
scanf("%s\n", b);
len = strlen(a);
}
int getmin(st c)
{
int i = 0, j = 1, k = 0, tmp;
while (i < len && j < len && k < len)
{
tmp = c[i + k >= len ? i + k - len : i + k] - c[j + k >= len ? j + k - len : j + k];
if (!tmp) ++k;
else
{
if (tmp > 0)
i += k + 1;
else
j += k + 1;
if (i == j) ++j;
k = 0;
}
}
return min(i, j);
}
int main()
{
init();
int pa = getmin(a), pb = getmin(b);
for (int i = 0; i < len; ++i)
if (a[i + pa >= len ? i + pa - len : i + pa] != b[i + pb >= len ? i + pb - len : i + pb])
{printf("No"); return 0;}
printf("Yes\n");
for (int i = 0; i < len; ++i) printf("%c", a[i + pa >= len ? i + pa - len : i + pa]);
return 0;
}
事实上这样效率还可以提高。
我们不每次判断,改为复制一段到后面。
虽然有点麻烦,但实际上还没有判断的麻烦,而且快了N倍,1.36s的大数据变成0.31s
code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<climits>
#define ot "%d"
#define min(a, b) ({int _ = (a), __ = (b); _ < __ ? _ : __;})
#define maxlen 10000005
using namespace std;
typedef char st[maxlen];
st a, b, d;
int len;
void init()
{
freopen("necklace.in", "r", stdin);
freopen("necklace.out", "w", stdout);
gets(a);
len = strlen(a);
strcpy(d, a);
strcat(a, d);
gets(b);
strcpy(d, b);
strcat(b, d);
}
void getmin(st &c)
{
int i = 0, j = 1;
while (j < len)
{
int w = 0;
while (c[i + w] == c[j + w] && w < len) ++w;
if (w == len) break;
if (c[i + w] < c[j + w])
j += w + 1;
else
{
i += w + 1;
if (i < j) i = j;
j = i + 1;
}
}
memset(d, 0, sizeof d);
memcpy(d, c + i, sizeof(char)* len);
d[len] = 0;
memcpy(c, d, sizeof(d));
}
int main()
{
init();
getmin(a), getmin(b);
if (!strcmp(a, b))
printf("Yes\n%s", a);
else
printf("No");
return 0;
}
话说忘记strcmp是相同返回0了,弄反,调试半天..
string版
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<climits>
#define ot "%d"
#define min(a, b) ({int _ = (a), __ = (b); _ < __ ? _ : __;})
using namespace std;
string a, b;
int len;
void init()
{
freopen("necklace.in", "r", stdin);
freopen("necklace.out", "w", stdout);
cin >> a >> b;
len = a.length();
}
void getmin(string &x)
{
x = x + x;
int i = 0, j = 1;
while (j <= len)
{
int k = 0;
while (k < len && x[i + k] == x[j + k]) ++k;
if (k == len) break;
if (x[i + k] < x[j + k])
j += k + 1;
else
{
if (i + k + 1 <= j)
i = j;
else
i += k + 1;
j = i + 1;
}
}
x = x.substr(i, len);
}
int main()
{
ios::sync_with_stdio(false);
init();
getmin(a), getmin(b);
if (a == b)
cout << "Yes" << endl << a << endl;
else
cout << "No";
return 0;
}
本来慢的要死,后来发现是cin cout的问题,果断ios::sync_with_stdio(false); 然后0.5s左右。
不过string更好写就是。
本文介绍了一种寻找字符串最小表示法的方法,并通过比较两个字符串的最小表示法来判断它们是否同构。提供了三种不同实现方式的代码示例,包括C风格字符串处理、内存拷贝优化以及使用标准模板库string的高效实现。
2005

被折叠的 条评论
为什么被折叠?



