HDU 4162 Shape Number【字符串最小表示】

Problem Description

In computer vision, a chain code is a sequence of numbers representing directions when following the contour of an object. For example, the following figure shows the contour represented by the chain code 22234446466001207560 (starting at the upper-left corner).


Two chain codes may represent the same shape if the shape has been rotated, or if a different starting point is chosen for the contour. To normalize the code for rotation, we can compute the first difference of the chain code instead. The first difference is obtained by counting the number of direction changes in counterclockwise direction between consecutive elements in the chain code (the last element is consecutive with the first one). In the above code, the first difference is
00110026202011676122
Finally, to normalize for the starting point, we consider all cyclic rotations of the first difference and choose among them the lexicographically smallest such code. The resulting code is called the shape number.
00110026202011676122
01100262020116761220
11002620201167612200
...
20011002620201167612
In this case, 00110026202011676122 is the shape number of the shape above.
Input
The input consists of a number of cases. The input of each case is given in one line, consisting of a chain code of a shape. The length of the chain code is at most 300,000, and all digits in the code are between 0 and 7 inclusive. The contour may intersect itself and needs not trace back to the starting point.
Output
For each case, print the resulting shape number after the normalizations discussed above are performed.
Sample Input
22234446466001207560
12075602223444646600
Sample Output
00110026202011676122
00110026202011676122

分析:

(1)利用两个指针p1, p2。初始化时p1指向s[0], p2指向s[1]。

(2)k = 0开始,检验s[p1+k]s[p2+k]对应的字符是否相等,如果相等k++,一直下去,直到找到第一个不同,(k试了一个字符串的长度也没找到不同,则那个位置就是最小表示位置,算法终止并返回)。则该过程中,s[p1+k]s[p2+k]的大小关系,有三种情况:

    (A).s[p1+k] > s[p2+k],则p1滑动到p1+k+1---s1[p1->p1+k]不会

      是该循环字符串的“最小表示”的前缀。

    (B). s[p1+k] > s[p2+k],则p1滑动到p1+k+1处,原因同上。

    (C). s[p1+k] = s[p2+k],则k++if (k == len)返回结果。

    注:这里滑动方式有个小细节,若滑动后p1 == p2,将正在变化的那个指针再+1。直到p1p2把整个字符串都检验完毕,返回两者中小于len的值。

(3)  如果k == len则返回p1p2中的最小值

      如果p1 >= len  则返回p2

    如果p2 >= len  则返回p1

(4)  进一步的优化,例如:p1要移到p1+k+1时,如果p1+k+1 <= p2的话,可以直接把p1移到p2之前,因为,p2p2+k已经检验过了该前缀比以p1p1+k之间任何一个位前缀都小;p2时的类似,移动到p1+1

code:

 

View Code
#include<stdio.h>
#include<string.h>
#define min(a,b)((a)<(b))?(a):(b)
int Min(char s[],int len)
{
int i=0,j=1,k=0;
while(i<len&&j<len&&k<len)
{
if(s[(i+k)%len]==s[(j+k)%len])
k++;
else
{
if(s[(i+k)%len]>s[(j+k)%len])
i+=k+1;
else
j+=k+1;
if(i==j)
j++;
k=0;
}
}
return min(i,j);
}
char s[300001];
int main()
{
int i,len,k;
char tmp;
while(scanf("%s",s)!=EOF)
{
len=strlen(s);
tmp=s[0];
for(i=0;i<len-1;i++)
s[i]=(s[i+1]+8-s[i])%8+'0';
s[i]=(tmp+8-s[i])%8+'0';
k=Min(s,len);
for(i=k;i<len;i++)
printf("%c",s[i]);
for(i=0;i<k;i++)
printf("%c",s[i]);
printf("\n");
}
return 0;
}



posted @ 2012-03-14 18:27  'wind  阅读(306)  评论(0编辑  收藏  举报