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
    评论
题目描述 给出一个$n\times m$的矩阵,每个位置上有一个非负整数,代表这个位置的海拔高度。一开始时,有一个人站在其中一个位置上。这个人可以向上、下、左、右四个方向移动,但是只能移动到海拔高度比当前位置低或者相等的位置上。一次移动只能移动一个单位长度。定义一个位置为“山顶”,当且仅当从这个位置开始移动,可以一直走到海拔高度比它低的位置上。请问,这个矩阵中最多有多少个“山顶”? 输入格式 第一行两个整数,分别表示$n$和$m$。 接下来$n$行,每行$m$个整数,表示整个矩阵。 输出格式 输出一个整数,表示最多有多少个“山顶”。 样例输入 4 4 3 2 1 4 2 3 4 3 5 6 7 8 4 5 6 7 样例输出 5 算法1 (递归dp) $O(nm)$ 对于这道题,我们可以使用递归DP来解决,用$f(i,j)$表示以$(i,j)$为起点的路径最大长度,那么最后的答案就是所有$f(i,j)$中的最大值。 状态转移方程如下: $$ f(i,j)=\max f(x,y)+1(x,y)是(i,j)的下一个满足条件的位置 $$ 注意:这里的状态转移方程中的$x,y$是在枚举四个方向时得到的下一个位置,即: - 向上:$(i-1,j)$ - 向下:$(i+1,j)$ - 向左:$(i,j-1)$ - 向右:$(i,j+1)$ 实现过程中需要注意以下几点: - 每个点都需要搜一遍,因此需要用双重for循环来枚举每个起点; - 对于已经搜索过的点,需要用一个数组$vis$来记录,防止重复搜索; - 在进行状态转移时,需要判断移动后的点是否满足条件。 时间复杂度 状态数为$O(nm)$,每个状态转移的时间复杂度为$O(1)$,因此总时间复杂度为$O(nm)$。 参考文献 C++ 代码 算法2 (动态规划) $O(nm)$ 动态规划的思路与递归DP类似,只不过转移方程和实现方式有所不同。 状态转移方程如下: $$ f(i,j)=\max f(x,y)+1(x,y)是(i,j)的下一个满足条件的位置 $$ 注意:这里的状态转移方程中的$x,y$是在枚举四个方向时得到的下一个位置,即: - 向上:$(i-1,j)$ - 向下:$(i+1,j)$ - 向左:$(i,j-1)$ - 向右:$(i,j+1)$ 实现过程中需要注意以下几点: - 每个点都需要搜一遍,因此需要用双重for循环来枚举每个起点; - 对于已经搜索过的点,需要用一个数组$vis$来记录,防止重复搜索; - 在进行状态转移时,需要判断移动后的点是否满足条件。 时间复杂度 状态数为$O(nm)$,每个状态转移的时间复杂度为$O(1)$,因此总时间复杂度为$O(nm)$。 参考文献 C++ 代码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值