UVA10029 - Edit Step Ladders(LIS)

题目大意:UVA10029 - Edit Step Ladders(LIS)


题目大意:给你一个按照字典序读入的单词,然后要求你找出最长的序列,要求这个最长的序列也要满足字典序,并且后一个是由前一个单词,由在任意的地方替换,增加,删除一个字符变换来的。


解题思路:LIS。但是这里的O(n^2) 25000,超时。但是查找符合的单词有个规律,符合变换要求的单词的长度是有要求的,必须相差小于等于1.并且数据中相同长度的单词不会超过45个,那么就可以把这些单词按照长度分类,那么查找的时候就是45 * 3.省下很多的时间。然后就是单词变换,这里分替换,和删除(插入是一样的)。这种做法是因为数据的原因,正解应该是将每个单词的变换的可能都变换出来(可以预处理+hash),然后再用二分查询找到是否有对应的单词。少了return,wa了无数次。真的要细心。


代码:

#include <cstdio>
#include <cstring>

const int maxn = 25005;
const int maxnL = 20;

char word[maxn][maxnL];
int n;
int l[maxn];//单词的长度
int dp[maxn];
int kind[maxnL][maxn]; //长度分类
int c[maxnL];

int Max (const int a, const int b) { return a > b? a: b; }

bool j_del (int a, int b) {//处理增加很删除

	int flag = 0;
	for (int i = 0, j = 0; i < l[b]; i++) {

		if (word[b][i] != word[a][j]) {

			if (flag)
				return false;
			else
				flag = 1;
			continue;
		}
		j++;
	}
	if (flag)
		return true;
	return false;
}

bool judge (int a, int b) {

	if (l[a] == l[b]) {//处理替换
			
		int flag = 0;
		for (int i = 0; i < l[a]; i++) {
			if (word[a][i] != word[b][i]) {
				if (flag)
					return false;
				else
					flag = 1;
			}
		}
		if (flag)
			return true;
		return false;

	} else if (l[a] == l[b] + 1) 
		return j_del(b, a);
	else if (l[b] == l[a] + 1) 
		return j_del(a, b);
	else
		return false;
}

void search (int len, int i) {	

	for(int j = 0; j < c[len]; j++) 	
		if(i > kind[len][j] && judge (kind[len][j], i)) { 
			dp[i] = Max (dp[i], dp[kind[len][j]] + 1);
		}
}

void handle () {

	for (int i = 1; i < n; i++) {

		search (l[i] - 1, i);
		search (l[i], i);
		search (l[i] + 1, i);
/*		for (int j = 1; j < i; j++) 
			if (judge(j, i))
				dp[i] = Max (dp[i], dp[j] + 1);*/
	}
}

int main () {

	n = 1;
	memset (c, 0, sizeof (c));
	while (gets(word[n]) != NULL) {
		l[n] = strlen (word[n]);
		kind[l[n]][c[l[n]]++] = n;
		n++;
	}

	for (int i = 1; i < n; i++)
		dp[i] = 1;

	handle ();

	int ans = 0;
	for (int i = 1; i < n; i++) 
		ans = Max (ans, dp[i]);

	printf ("%d\n", ans);
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值