HDU2609How many

How many

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


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
 


题目大意:

题目要求就是要我们找出不同的项链串有多少条,那么怎么判断他们是是否为同一条项链呢:比如给出字符串 0110       那么将这个字符串(也就是项链旋转)可以得到  0110->1100->1001->0011->0110 那么这些字符串其实都是这个属于这个字符串。

分析:

把它看做项链,那么不管我们怎么旋转一条项链,不管我们以哪个位置为起始点,它的本质还是这条项链没有变。这里其实设计到了一个算法-->“字符串的最小表示法” ,推荐一篇博文,个人觉得讲得还可以恩: http://blog.csdn.net/cclsoft/article/details/5467743

刚开始写这题的时候我也是进入了一个误区,导致了一直WA后来还因为数组开小了,提示超时(这个还真是没搞明白,应该提示RE才对);开始的时候一直以为,每条项链都是(也就是每个字符串都是旋转一次得到了下一个字符串),所以认为是简单的模拟,在对题目的判断上就出错了,其实题目可以给出 这样的数据  比如  1100     0011     而不是1100   1001,其实它还是同一串项链,也就是说他们的最小串是相等的;然后用解决了这个问题,又出现了个新的问题,就是同一条项链在题目中给出的顺序可能有差别 比如 1100  1000  1001  0100 其实这里只有两串不同的项链,但是可能我给的算法就会给出答案 4;所以这里我们需要把相同的项链归到一起,那么我们只要对其排个序就好了(sort一下)相同的就到一起了,然后就好处理了;

用“字符串的最小表示法”,可以确定了,最小的串在原串中的起始位置,那么我们就可以根据这个直接将最小串给表示出来,然后找出不一样的最小串有多少个就可以得出有多少条不同的项链了;然后用sort排序下将相同的项链放到一起,然后循环查找下,当找到了前面和后面有不一样的最小串的时候,那么其就是不同的项链;最终得到答案;


给出AC代码:

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>

using namespace std;

struct neNODE
{
	char strs[1005];

}necklace[10005];

char str[1005];


bool cmp(neNODE a, neNODE b)
{
	return strcmp(a.strs,b.strs)<0;
}

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);
}


int main()
{
	int n;

	while (cin>>n)
	{
		int len;
		for (int i = 0; i < n; i++)
		{
			cin >> str;
			len = strlen(str);
			int Minpos = MinimumRepresentation(str, len);//用最小串表示法得到最小串在原串中的起始位置;
			int k, j;
			for (k = 0, j = Minpos; j < len; j++) //得到最小串
			{
				necklace[i].strs[k++] = str[j];
			}
			for (j = 0; j < Minpos; j++)//得到最小串
			{
				necklace[i].strs[k++] = str[j];
			}
			necklace[i].strs[k] = '\0';
		}
		int count = 1;
		sort(necklace, necklace + n, cmp); //排序,将相同的项链放到一起
		for (int i = 1; i < n; i++)
		{
			if (strcmp(necklace[i].strs, necklace[i - 1].strs) != 0)
			{
				//cout << se << endl;
				count++;
			}
		}
		cout << count << endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值