UVa 1401 - Remember the Word

题目:有一个长串,和一组单词组成的字典,问可以将长串完全拆分成单词的方法数。

分析:字典树,动态规划(dp)。利用字典树做存储和查询,dp求解。

          状态定义:f(i)为串str[1..i]的拆分情况,为了方便计算这里长串从下标1开始;

          转移方程:f(i)= sum(f(j)),f(j)是str[j+1..i]存在字典中是,前缀的数量;

说明:好久没写题了,UVa上不去。

#include <cstdlib>
#include <cstring>
#include <cstdio>

/* Tire define */
#define nodesize 200002        //节点个数 
#define dictsize 26            //字符集大小  

typedef struct _tire_node
{
    int         flag;            //值域 
    _tire_node* next[dictsize];
}tire_node;
tire_node  dict[nodesize+1];
tire_node* Q[nodesize+1];
int        ID[256];
int        dp[300003];

class Tire
{
    private:
        int        size;
        tire_node* root;
    public:
        Tire() { 
			makeID(); 
			init(); 
		}
        void makeID() {
            for (int i = 0; i < 26; ++ i) {
                ID['a'+i] = i;
			}
        }
        void init() {
            memset(dict, 0, sizeof(dict));
            root = NULL; 
			size = 0; 
			root = newnode();
        }
        tire_node* newnode() {
            return &dict[size ++];
        }
        void insert(char* word) {
            tire_node* now = root;
            for (int i = 0; i < word[i]; ++ i) {
                if (!now->next[ID[word[i]]]) {
                    now->next[ID[word[i]]] = newnode();
				}
                now = now->next[ID[word[i]]];
            }
			now->flag = 1;
        } 
        int query(char* segment, int s, int e) {
            tire_node *now = root;
            for (int i = s; i <= e; ++ i) {
				if (now->next[ID[segment[i]]]) {
                	now = now->next[ID[segment[i]]];
				}else {
					return 0;
				}
            }
            return now->flag;
        }
}tire;
/* Tire  end */

char text[300003];
char word[101];

int main()
{
	int n, t = 1;
	while (~scanf("%s", &text[1])) {
		scanf("%d", &n);
		tire.init();
		for (int i = 0; i < n; ++ i) {
			scanf("%s",word);
			tire.insert(word);
		}
		
		memset(dp, 0, sizeof(dp));
		dp[0] = 1;
		for (int i = 1; text[i]; ++ i) {
			dp[i] = 0;
			for (int j = i; j > 0 && i-j < 100; -- j) {
				if (tire.query(text, j, i)) {
					dp[i] = (dp[i] + dp[j-1]) % 20071027;
				}
			}
		}
		printf("Case %d: %d\n", t ++, dp[strlen(&text[1])]);
		
		if (getchar() == EOF) {
			break;
		}
	}
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值