tclh123

[编辑长度/字符串dp] HDOJ - 4323 Magic Number

http://acm.hdu.edu.cn/showproblem.php?pid=4323

关于编辑距离这篇博客讲得比较清楚, 还把第四种编辑"邻位交换"加进去了.

现在突然觉得原来字符串dp有好多,为什么?因为字符串是典型的无后效性吧,这种两串来二维dp的比如最长公共字串也是经典dp了.

状态描述:

// 状态: d[i][j] 表示 串a的 i 长子串(0~i-1), 变到 串b的 j 长子串 要最少花费多少操作(即a到b的编辑距离).

状态转移:

(la lb表示串长度.)

	memset(d, 0, sizeof(d));
	REP(la)
		d[i][0] = i;
	REP(lb)
		d[0][i] = i;
	FOR(i, 1, la)	// 这里 i , j 表示 长度, 不是串下标!!(因为如果是下标的话, 0长度子串下标为-1无法表示, 除非用记忆化搜索解)
		FOR(j, 1, lb)
	{
		int del = d[i][j-1]+1;
		int ins = d[i-1][j]+1;
		int sub = d[i-1][j-1]+!(a[i-1] == b[j-1]);
		d[i][j] = min(min(del, ins), sub);
	}

问题的解:

	return d[la][lb];

好像还有什么很厉害的BK树....以后再看吧...

用dp解,第一次交800+ms, 然后把串长调低点再交600+ms, 然后把min函数自己写inline, 484ms....还是挫...

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
int Rint() { int x; scanf("%d", &x); return x; }
#define FOR(i, a, b) for(int i=(a); i<=(b); i++)
#define FORD(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(x) for(int i=0; i<(x); i++)
typedef long long int64;
#define INF (1<<30)
#define bug(s) cout<<#s<<"="<<s<<" "

//	多决策dp, 字符串dp, 字符串编辑距离
// 状态: d[i][j] 表示 串a的 i 长子串(0~i-1), 变到 串b的 j 长子串 要最少花费多少操作(即a到b的编辑距离).

#define MAXLEN 12	//串长
#define MAXN 1502	//目标串个数
#define MAXM 1002	//源串个数
int d[MAXLEN+1][MAXLEN+1];		//d[源][目标], 准确来讲下标应为 MAXLEN+1
int la, lb;	//la源串长
int n, m;		//目标串个数, 源串个数
char strb[MAXN][MAXLEN];	//目标串s
char stra[MAXLEN];	//源串
int lim;	// 阀值

inline int min(int a,int b)  
{  
    return (a<b)?a:b;  
}

int dp(char* a, char* b)
{
	memset(d, 0, sizeof(d));
	REP(la)
		d[i][0] = i;
	REP(lb)
		d[0][i] = i;
	FOR(i, 1, la)	// 这里 i , j 表示 长度, 不是串下标!!(因为如果是下标的话, 0长度子串下标为-1无法表示, 除非用记忆化搜索解)
		FOR(j, 1, lb)
	{
		int del = d[i][j-1]+1;
		int ins = d[i-1][j]+1;
		int sub = d[i-1][j-1]+!(a[i-1] == b[j-1]);
		d[i][j] = min(min(del, ins), sub);
	}
	return d[la][lb];
}

int main()
{
	int T = Rint();
	FOR(t, 1, T)
	{
		printf("Case #%d:\n", t);
		n = Rint();
		m = Rint();
		REP(n)
		{
			scanf("%s", strb[i]);
		}
		REP(m)
		{
			int ans = 0;
			scanf("%s%d", stra, &lim);
			la = strlen(stra);
			FOR(j, 0, n-1)
			{
				int done = 0;
				lb = strlen(strb[j]);
				if(abs(la-lb)>lim){}
				else
				{
					int cnt = dp(stra, strb[j]);
					done = cnt<=lim? 1: 0;
				}
				if(done)
				{
					//bug(strb[j])<<endl;
					ans++;
				}
			}
			printf("%d\n", ans);
		}
	}
}


发表于 2012-08-02 17:23  泳裤王子  阅读(117)  评论(0编辑  收藏  举报
 

分类:

技术点:

相关文章: