关于北大ACM1002题目的普通代码

由于博主要退EE保平安,下半年估计会去日本早稻田进一步学习计算机,所以为了养成良好的代码习惯,每天开始锤北大ACM题库,就从最基本的1000题开始。养成良好的代码手感和代码思维我觉得是保持专业良好学习习惯的前提。

“纸上得来终觉浅,绝知此事要躬行”,这句话绝不是空穴来风,任何好的代码,任何干练得代码都需要你自己不断努力,不断练习才能够快速上手,虽然代码不需要你自己记住,但是你必须要会用,而会用的前提是你得对代码的每一寸土壤,每一寸皮肤都要有自己独特的感受,自己独到的见解,如此你才能够在茫茫多的程序员中找到你自己的路。

这番话为自己,也为了她。希望若干年后回国,我不希望我没办法给他一个未来。

好了下面走入正题,关于ACM1002题,不得不说,这道题虽然是基础题的范畴,但我还是觉得这道题放在这里还是有些困难了,特别是对比它后面几道题的难度(真的,后面1003,1004这些题简单到你无法相信)。

个人分析在于如下几个方面:

1、这个数组的范围上限有些大,我用VC2013专业版也没办法开出int a[100000][7]的二维数组,相信很多人告诉你,对于这种题目,最好不要开动态数组,直接开一个上限值,这样不会浪费时间。当然这样是对的,你开辟一个动态数组虽然说节省了内存,但是你需要自己管理,手动释放,这都是大把大把的时间啊,特别是现在存储空间成本越来越低的情况下,时间越发珍贵。所以这道题很多人的想法是开一个二维的动态数组。这点就已经有些困难了。因为二维的动态数组管理麻烦,传递麻烦,释放麻烦,最麻烦的是你不好改变数组位置;

2、排序!对很基础的一个算法,大抵基础的排序算法大概接近10种,算法导论这本书里几乎说了所有的排序算法,那么这道题,我试过把7位数直接转换为int型变量,然后使用随机快速排序进行处理,最后结果再对数字处理一下就可以得到结果了,然而,呵呵,事实上大数排序的耗时远远超过你的想象,这个算法自己试了一下,似乎是对的,待会会贴出来,在测试机上超时了,所以这个想法就GG了,博主后来直接用了最快的基数排序法,不愧是线性的排序方法,竟然用排序的解题方法把这道题解出来了;

3、当然了如果你就题论题,只是为了追求高速,低内存的话,其实这道题也不是非常的麻烦,你需要构建一个结构体,可以比较快速的删除元素是这个结构体唯一的要求,然后你可以归幂,比如后4位一起,前3位一起,然后使用桶排序的方法,统计每个值出现的次数,以后4位为例,你查看后4位的所有数据出现的频率,是1的统统使用结构体函数删除,只有大于1的才进行保留,然后再看前3位,同样的过程,这样可以吧测试机上给你的很大范围的数变成只有重复的数,然后在计算频率的过程中使用桶排序,很容易就快速搞定了,岂不美哉?

只不过博主没有用这种方法,因为博主想试一下,不就题论题,就排序一个二维数组是否可以达到题目要求呢》?事实上是可以的。代码如下。

#include<iostream>
using namespace std;

int ex(char num);//字符处理函数
void sort_two(int *a, int n);//二维数组排序函数

int main()
{
	int n = 0;
	int i, j = 0;
	int true_col = 0;
	int true_time = 0;
	cin >> n;
	int *a = new int[n*7]; //定义存储
	int *times = new int[n];//定义次数

	for (i = 0; i < n; i++)
	{
		char s[50];
		true_col = 0;
		times[i] = 1;
		cin >> s;
		for (j = 0; j < 50; j++)
		{
			if (s[j] == '-')
				continue;
			if (s[j] == ' ')
				continue;
			if (s[j] == NULL)
				break;
			a[i*7+true_col] = ex(s[j]);
			true_col = true_col + 1;
		}
	}
	sort_two(a, n);

	for (i = 0; i < n - 1; i++)
	{
		if (a[i*7+0] == a[(i + 1)*7+0] && a[i*7+1] == a[(i + 1)
			*7+1] && a[i*7+2] == a[(i + 1)*7+2] && a[i*7+3] == a[(i + 1)*7+3] 
			&& a[i*7+4] == a[(i + 1)*7+4] && a[i*7+5] == a[(i + 1)*7+
			5] && a[i*7+6] == a[(i + 1)*7+6])
		{
			times[true_time]++;
		}
		else
		{
			true_time = i + 1;
		}
	}
	true_col = 0;
	for (i = 0; i < n; i++)
	{
		if (times[i] != 1)
		{
		for (j = 0; j < 7; j++)
		{
			if (j == 3)
				cout << '-';
			cout << a[i*7+j];
		}
		cout << " " << times[i] << endl;
		}
		else true_col++;
	}
	if (true_col == n)
	{
		cout << "No duplicates." << endl;
	}
		delete[]a;
		a = NULL;
		delete[] times;
		times = NULL;
		return 0;
}

void sort_two(int *a, int n)
{
	int col = 0;//主循环位数
	int give = 0;
	int i = 0;//频率计数
	int j = 0;//普通计数
	int C[10];
	int *B = new int[n * 7]; //定义存储

	for (col = 6; col >= 0; col--)
	{
		for (i = 0; i<10; i++)
		{
			C[i] = 0;
		}
		for (j = 0; j < n; j++)
		{
			C[a[j*7+col]] = C[a[j*7+col]] + 1;
		}
		for (i = 1; i < 10; i++)
		{
			C[i] = C[i] + C[i - 1];
		}
		for (j = n - 1; j >= 0; j--)
		{
			for (give = 0; give < 7; give++)
			{
				B[(C[a[j*7+col]]-1)*7+give] = a[j*7+give];
			}
			C[a[j * 7 + col]] = C[a[j * 7 + col]] - 1;
		}
		for (j = 0; j < n; j++)
		{
			for (i = 0; i < 7; i++)
			{
				a[j*7+i] = B[j*7+i];
			}
		}
	}
	delete[]B;
	B = NULL;
}

int ex(char num)
{
	if ((int)num > 47 && (int)num < 58)
		return ((int)num - 48);
	if ((int)num >64 && (int)num < 68)
		return 2;
	if ((int)num >67 && (int)num < 71)
		return 3;
	if ((int)num >70 && (int)num < 74)
		return 4;
	if ((int)num >73 && (int)num < 77)
		return 5;
	if ((int)num >76 && (int)num < 80)
		return 6;
	if ((int)num >79 && (int)num < 84)
		return 7;
	if ((int)num >83 && (int)num < 87)
		return 8;
	if ((int)num >86 && (int)num < 90)
		return 9;
}
这个是通过的,你仔细观察这个就会发现其实速度还能更快的,因为我写到这里的时候实在是写不动了(你无法想象这道题困扰了我一个晚上殚精竭虑)于是就很任性的每次拍完序就重新复制一次,这是很浪费时间的,你可以交替着来,就是先a,b,然后再b,a如此反复会节省一些时间。

最后我还是得感慨一下,基数排序法真不是盖的。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值