1. 程式人生 > >poj1509 最小表示法

poj1509 最小表示法

學習一下最小表示法……,部分內容與此題無關。
1.起始問題 :比較兩個字串是否迴圈同構        比如說abca和caab是迴圈同構的(abca和acba不是迴圈同構) 2.複雜度較高的演算法       例舉A串的所有迴圈同構串 和B串作比較:abca,bcaa,caab,aabc挨個和caab比一邊       複雜度O(N^2)    能否優化到O(N)? kmp演算法顯然可以,但是kmp是針對匹配的,不是專門針對同構的,顯得有些麻煩 3.最小表示法,就是充分利用迴圈同構的特點,進行比較的一種演算法,兩個串如果迴圈同構,會有什麼特點? 比如以上例舉的四個abca的迴圈同構串abca,bcaa,caab,aabc,如果有一種對映,這四個字串對應的對映值相同,那比較起來就太快了 我們利用字串的字典序,把這四個都對映到aabc,那就可以很快比較了,具體還有一些細化,利用最小表示的起始位置等等 具體的演算法和證明,周源2003年國家隊論文
寫的不錯 4.最小表示的最靠近串首的起始位置計算 abca的同構串中aabc最小,那麼要記錄下aabc開頭的a在abca中的位置,就不用記錄abca了,所以只要算出這個位置,就可以進行字串之間迴圈同構的比較     複雜度O(N) 我參考了這篇部落格http://blog.csdn.net/zy691357966/article/details/39854359 對於一個字串,i開始指向0,j開始指向1,演算法的過程中,i和j中小的數表示當前認為的合理位置,大的數表示從這個數開始可能會找到更合理的位置 (開始認為從最開始的位置是合理的 i= 0,只有在0後面才可能找到更合理的,所以j=1) 然後把字串複製一遍到末尾(方便迴圈) 每次從i+0和j+0開始比較,如果一直比較串長度個,都一樣,那麼恭喜你,i和j中的最小者就是答案了(為什麼自己想(實際上是我懶,要結合i和j所代表的意義)) 如果比較到i+k和j+k不相等,結束迴圈  。 【下面這段是關鍵】 s(i,i+k-1)的每一位和s(j,j+k-1)的每一位對應相等,而如果s[i+k] > s[j+k],則i到s(i+x,i+k)顯然比s(j+x,j+k)大,(0<=x<=K) 那麼最小表示的開始位置就不可能是i到i+k【s(x,y)表示x到y的字串】 所以這個時候把i置為i+k+1,類似的,如果s[j+k] > s[i+k]就把j置為j+k+1 【上面那段是關鍵】 如果某一次加完之後i和j相等,那就和開始的時候一樣,不好比較了,這個時候把i或者j+1,繼續演算法 每一次這樣的迴圈結束後,如果i或者j超出m的範圍了,那麼另外一個就是解了! 上一下自己的程式碼……
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
int  minpre(char s[])
{
	int m = strlen(s);
	memcpy(s + m, s,m*sizeof(char));
	int i = 0,j = 1;//i表示從i往後是有可能的,j表示下一個試探的位置 
	while(j < m && i < m) 
	{
		int k;
		for (k = 0;s[i + k] == s[j + k] && k < m; k++)
		if(k == m ) return min(i,j);//如果相等了,那最小的就是答案 
		if(s[i + k] > s[j + k]) i = i + k + 1;//i到i+k開始的都不可能 
		else (j = j + k + 1);//同上 
	    if (i == j) j++;//剛好相等,重新比較 
	    
	}
	if(i < m) return i;
	else return j;
}

int main()
{
    char s[20005];
	int n;
	scanf("%d",&n);
	while(n--)
	{
		scanf("%s",s);
	    printf("%d\n",minpre(s) + 1);
	}	
} 
第一次發部落格,小緊張……有點捉急