字典树 之 hdu 4099

//  [7/4/2014 Sjm]
关键:“截断”处理
/*
在此题上花了好久,最后在大牛提醒下才AC,还是要多见题型、多练啊。。。
 
如果接触字典树,对于此题,大体的思路会有的
1)建立字典树:根据前 100000 斐波那契数
2)根据输入的数字串去字典树中搜索。
 
需要解决的问题:
1)记录最先到达此处节点的斐波那契数的标号:字典树结构体中加入一个 number 解决
2)两个数字字符串相加(我之前写的一个,过掉之后,翻看其他人代码,发现自己写的又丑又长,果断把方法学过来。。。)
 
***************************************会遇到的问题**********************************
1)由于计算前 100000 斐波那契数,而实际有用的却只有前 40 位,所以要对所求值做“截断”处理。
   也就是说,当所求斐波那契数长度大于50时,截取掉个位,保留不包含个位的高位,这样每次计算
   出的值可以保证在50多位。(开数组中可以大一些,若MLE,再减小)
2)存入字典树时,最多存入40位即可。(多一些更保险,但防止MLE)
*************************************************************************************
 
话说最坑的是把代码中两个变量弄混了,找了好久的 bug 。。。。悲剧啊大哭。。。不过又见到了一种之前没见过的题型吐舌头
*/
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAX = 10, MAX_LEN = 55;

char t_str[MAX_LEN];
void Str_Add(char str1[], char str2[], char str[]) {
	int len1 = strlen(str1) - 1, len2 = strlen(str2) - 1;
	int len = 0, to_add = 0;
	int pos1, pos2, pos;
	while ((len1 >= 0) || (len2 >= 0)) {
		if (len1 < 0) pos1 = 0;
		else pos1 = str1[len1] - '0';
		if (len2 < 0) pos2 = 0;
		else pos2 = str2[len2] - '0';

		pos = pos1 + pos2 + to_add;
		t_str[len++] = pos % 10 + '0';
		to_add = pos / 10;

		len1--;
		len2--;
	}
	if (to_add > 0) {
		t_str[len++] = to_add + '0';
	}
	for (int i = 0; i < len; i++) {
		str[i] = t_str[len - 1 - i];
	}
	str[len] = '\0';
}

struct Trie {
	Trie* next[MAX];
	int number;

	Trie() {
		memset(next, NULL, sizeof(next));
		number = -1;
	}
};

Trie* Root = new Trie;


void CreTrie(char str[], int num)
{
	int len = strlen(str);
	Trie* p = Root;
	for (int i = 0; i < len && i < 40; i++) {
		int pos = str[i] - '0';
		if (!p->next[pos]) {
			p->next[pos] = new Trie;
		}
		p = p->next[pos];
		if (-1 == p->number) {
			p->number = num;
		}
	}
}


int SeaTrie(char str[])
{
	int len = strlen(str);
	Trie* p = Root;
	for (int i = 0; i < len; i++) {
		int pos = str[i] - '0';
		if (!p->next[pos]) {
			return -1;
		}
		else {
			p = p->next[pos];
		}
	}
	return p->number;
}

void DelTrie(Trie * T) {
	for (int i = 0; i < MAX; i++) {
		if (T->next[i]) {
			DelTrie(T->next[i]);
		}
	}
	delete[] T;
}

void Get_Fib()
{
	char str1[MAX_LEN] = "1";
	char str2[MAX_LEN] = "1";
	char str[MAX_LEN];
	CreTrie(str1, 0);
	CreTrie(str2, 1);

	for (int i = 2; i < 100000; i++) {

		int len1 = strlen(str1);
		int len2 = strlen(str2);
		if (len2 > 50) {
			str1[len1 - 1] = 0;
			str2[len2 - 1] = 0;
		}

		Str_Add(str1, str2, str);
		CreTrie(str, i);
		strcpy(str1, str2);
		strcpy(str2, str);
	}
}

int main()
{
	//freopen("input.txt", "r", stdin);
	Get_Fib();
	int T;

	scanf("%d", &T);
	char str[45];
	for (int i = 1; i <= T; i++) {
		scanf("%s", str);
		printf("Case #%d: %d\n", i, SeaTrie(str));
	}
	DelTrie(Root);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值