ACM最小表示法 最大表示法 模板 及其使用环境 判断字符串循环重构

#include <iostream>
#include <string>
using namespace std;
/*
用最小表示法求字符串S的最小字典序
返回字典序最小的串的首字母位置
*/
int minSub(char * p)
{
 int i=0,j=1,len=strlen(p),k=0;
 while(i<len && j<len &&k< len)
 {
  if(k==len) break;
  if(i==j) j++;
  int ni=i+k , nj=j+k;
  if(ni>=len) ni-=len;
  if(nj>=len) nj-=len;
  if(p[ni] > p[nj]) { i+=k+1; k=0; }
  else if(p[ni] < p[nj]) { j+=k+1; k=0; }
  else  k++;
 }
 return i;
}/*注意返回的值是最小字典序字符串的首位置  这时候最小序列字符串依旧保存在pat中, 只不过开始位置为 该函数的返回值 假设为
a  则把a之后的字符放进一个我们准备好的字符串中 , 之后把a之前的字符继续放进去 这个新的字符串就是最小的了*/

 

最大表示法:

int getmax()  //最大表示法
{
   int len = strlen(pat);
   int i=0,j=1,k=0;
   while(i<len && j<len && k<len)
   {
       int t = pat[(i+k)%len] - pat[(j+k)%len];
       if(!t) k++;
       else
       {
           if(t>0) j = j+k+1;
           else i = i+k+1;
           if(i == j) j++;
           k = 0 ;
       }
   }
   return i<j?i:j;
}

 

另外  最大最小表示法返回的值都是  该字符串的所有字符串中的第几个  即rank


例题分析 :

hdu 2609How many—–最小表示法判断字符串循环重构

How many

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 809 Accepted Submission(s): 307

Problem Description
Give you n ( n < 10000) necklaces ,the length of necklace will not large than 100,tell me How many kinds of necklaces total have.(if two necklaces can equal by rotating ,we say the two necklaces are some). For example 0110 express a necklace, you can rotate it. 0110 -> 1100 -> 1001 -> 0011->0110.

Input
The input contains multiple test cases.
Each test case include: first one integers n. (2<=n<=10000)
Next n lines follow. Each line has a equal length character string. (string only include ’0′,’1′).

Output
For each test case output a integer , how many different necklaces.

Sample Input
4
0110
1100
1001
0011
4
1010
0101
1000
0001

Sample Output
1
2

题目大意 : 有一条项链, 0,1 代表不同的珠子。 输入一个数n,然后输入n条项链。 但是可能出现同样的,求有多少条不同的项链。

例如  题中的例子 0110 -> 1100 -> 1001 -> 0011->0110     这五种输入 是同一条项链,因为,项链是环状 的。

解题思路: 就是环状字符串的判重。主要是求 字符串 的 最小表示。

 

#include<map>
#include<cstdio>
#include<string>
using namespace std;
int minSub(char *a);
int main()
{
//	freopen("in.txt","r",stdin);
	map <string,int> p;
	int n;
	char a[200],b[200];
	while(scanf("%d",&n)!=EOF)
	{
		p.clear();	  //之前没初始化 错了一次。
		int sum=0;
		while(n--)
		{
			b[0]='\0';
			scanf("%s",a);
			int index=minSub(a);	//求出最小表示的起点
			strcat(b,a+index);
			strncat(b,a,index);		//求出来的b就是最小表示
			//strncat 是指把a的前index个字符添加到b的末尾
			if(! p[b]) {					//map函数
				sum++; p[b]=1;
			}
		}
		printf("%d\n",sum);
	}
	return 0;
}
int minSub(char * a)				  //之前写过的,直接当模板用
{
	int i=0,j=1,len=strlen(a),k=0;
	while(i<len && j<len &&k< len)
	{
		if(k==len) break;
		if(i==j) j++;
		int ni=i+k , nj=j+k;
		if(ni>=len) ni-=len;
		if(nj>=len) nj-=len;
		if(a[ni] > a[nj]) { i+=k+1; k=0; }
		else if(a[ni] < a[nj]) { j+=k+1; k=0; }
		else	 k++;
	}
	return i;
}



 

 

你可能感兴趣的:(ACM最小表示法 最大表示法 模板 及其使用环境 判断字符串循环重构)