zoukankan      html  css  js  c++  java
  • 最小表示法

    用途

    给一个首尾相连的字符串,找一个位置,从这个位置往后形成一个字符串,使字符串的字典序最小

    算法

    定义三个指针(i=0),(j=1),(k=0)(i)(j)是当前判断的位置,(k)是相同的串的长度,表示(str[i...i+k])(str[j...j+k])相同。
    (str[i+k]==str[j+k])时,显然,(k++)
    (str[i+k] > str[j+k])时,发现(i+k)位置的字典序要比(j+k)位置的字典序大,显然,(str[j...j+k])的比(str[i...i+k])的更优,字典序更小,那(i)位置就不能做开头了,必须要往后走,这时(i=i+k+1)
    (str[i+k] < str[j+k])(j=j+k+1)
    很显然的是(i)不能等于(j),所以当(i==j)时,(j(或i)++)
    最后(i)(j)中较小的那一个就是要找的字符串开始的位置

    模板

    工艺

    /*
    最小表示法 
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e6 + 10;
    int n, m;
    int a[N];
    template<class T>inline void read(T &x) {
    	x = 0; int f = 0; char ch = getchar();
    	while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
    	while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    	x = f ? -x : x;
    	return ;
    }
    
    int Min() {
    	int i = 0, j = 1, k = 0;
    	while (i < n && j < n && k < n) {
    		if (a[(i + k) % n] == a[(j + k) % n]) k++;              //相等k往后移
    		else {
    			if (a[(i + k) % n] > a[(j + k) % n]) i += k + 1;    //如上文,i的字典序比j的大
    			else j += k + 1;                                    //i的字典序比j的小
    			if (i == j) j++;                                    //i不能等于j
    			k = 0;                                              //k置0
    		}
    	}
    	return min(i, j);
    }
    
    int main() {
    	read(n);
    	for (int i = 0; i < n; ++i) read(a[i]);
    	int ans = Min();
    	for (int i = 0; i < n; ++i) printf("%d ", a[(i + ans) % n]);
    	return 0;
    }
    

    poj1509 Glass Beads

    /*
    最小表示法 
    */
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    const int N = 1e5 + 10;
    int t, n;
    char s[N];
    
    int Min() {
    	int i = 0, j = 1, k = 0;
    	while (i < n && j < n && k < n) {
    		if (s[(i + k) % n] == s[(j + k) % n]) k++;
    		else {
    			if (s[(i + k) % n] > s[(j + k) % n]) i += k + 1;
    			else j += k + 1;
    			if (i == j) j++;
    			k = 0;
    		}
    	}
    	return min(i, j);
    }
    
    int main() {
    	cin >> t;
    	while (t--) {
    		memset(s, 0, sizeof(s));
    		cin >> s;
    		n = strlen(s);
    		printf("%d
    ", Min() + 1);
    	}		
    	return 0;
    }
    

    简单小证明

    为什么是(i=i+k+1)呢,我们任取区间([1,k])之间的一个数(k'),因为(str[i+k]>str[j+k]),所以(k')不论取何值,我们发现(str[j+k'...j+k])总是比(str[i+k'...i+k])优,所以(i+k')不能做开头,因为(k')可以取到(k),所以(i+k)不能做开头,所以(i=i+k+1)

  • 相关阅读:
    win8 开发之旅(1) 连连看游戏开发 前奏
    win8 开发之旅(2) 连连看游戏开发 项目错误的总结
    常见的排序算法五——堆排序
    我与mongodb 二三事(1)
    常见的排序算法四——直接选择排序
    我与mongodb 二三事(2)
    oracleHelper的使用
    公司A、公司B、公司C……
    javascript调用C#后台程序执行查询
    通过翻译学英语
  • 原文地址:https://www.cnblogs.com/lykkk/p/10425418.html
Copyright © 2011-2022 走看看