POJ 1732 Phone numbers(DP)

思路:先把字符串转化为对应数字,然后把这些插入SET(其实建个字典树会更好一些),然后每次dp[i] = max(dp[i], dp[j] + 1) {存在i到j的字符串)

代码:

#include <cstdio>
#include <cstring>
#include <map>
#include <string>
using namespace std;

typedef unsigned long long ull;

const int N = 105;
const ull x = 123;
const int INF = 0x3f3f3f3f;

char str[50005][55], to[255];
char s[N];

int n;
ull hash[N], mi[N];

//map<ull, int> id;
map<string, int> id;

int dp[N], path[N][2];

void print(int u) {
    if (path[u][0] == 0) {
	printf("%s", str[path[u][1]]);
	return;
    }
    print(path[u][0]);
    printf(" %s", str[path[u][1]]);
}

char ss[50005][55];

int main() {
    to['i'] = to['j'] = '1';
    to['a'] = to['b'] = to['c'] = '2';
    to['d'] = to['e'] = to['f'] = '3';
    to['g'] = to['h'] = '4';
    to['k'] = to['l'] = '5';
    to['m'] = to['n'] = '6';
    to['p'] = to['r'] = to['s'] = '7';
    to['t'] = to['u'] = to['v'] = '8';
    to['w'] = to['x'] = to['y'] = '9';
    to['o'] = to['q'] = to['z'] = '0';
    mi[0] = 1;
    for (int i = 1; i < N; i++) mi[i] = mi[i - 1] * x;
    while (~scanf("%s", s + 1)) {
	int m = strlen(s + 1);
	for (int i = 1; i <= m; i++)
	    hash[i] = hash[i - 1] * x + s[i];
	scanf("%d", &n);
	id.clear();
	for (int i = 1; i <= n; i++) {
	    scanf("%s", str[i]);
	    int len = strlen(str[i]);
	    ull s = 0;
	    for (int j = 0; j < len; j++) {
		s = s * x + to[str[i][j]];
		ss[i][j] = to[str[i][j]];
	    }
	    ss[i][len] = '\0';
	    //id[s] = i;
	    id[ss[i]] = i;
	}
	memset(dp, INF, sizeof(dp));
	dp[0] = 0;
	char sb[105];
	for (int i = 1; i <= m; i++) {
	    for (int j = 0; j < i; j++) {
		strcpy(sb, s + j + 1);
		sb[i - j] = '\0';
		ull tmp = hash[i] - hash[j] * mi[i - j];
		if (id.count(sb)) {
		    if (dp[i] > dp[j] + 1) {
			dp[i] = dp[j] + 1;
			path[i][0] = j;
			path[i][1] = id[sb];
		    }
		}
	    }
	}
	if (dp[m] == INF) printf("No solution.\n");
	else {
	    print(m);
	    printf("\n");
	}
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值