您的位置:首页 > 其它

hdu 4323 Magic Number 2012多校训练第三场1004题 BK树

2012-07-31 20:58 435 查看
今天下午进行了第三场的多校,表示被虐成了狗……

1004题当时感觉想暴力,毛估复杂度是1000*1500*10*10……这还是单case的,所以一直没敢敲……直到最后发现全场几十支队伍都过了,开始敲……结果没想清楚最终WA到死

晚上的时候回基地写了个暴力解法,375ms过了,感觉时间卡的也不紧……需要稍作优化,两个字符串长度之差大于要求的编辑距离时就不用再去dp了,dp的状态转移和求最长公共子序列非常像

for(int i=1; i<=l1; i++)
for(int j=1; j<=l2; j++)
if(s1[i-1]!=s2[j-1])
dp[i][j] = min(min(dp[i-1][j-1]+1,dp[i-1][j]+1),dp[i][j-1]+1);
else dp[i][j] = min(min(dp[i-1][j-1],dp[i-1][j]+1),dp[i][j-1]+1);dp[i][j]表示第一个的前i个字符和第二个的前j个字符的编辑距离
后来看了结题报告,知道了BKTree这种东西,然后去看了matrix67大神的博客,学了下这个数据结构……感觉和trie树基本雷同,具体的还是看看大神的博客吧

BK树解法代码如下:(我肯定写残了……只比我的暴力程序快了两倍)

#include <cstdio>
#include <cstring>
const int MAX = 1510;
const int LEN = 15;
char s2[LEN];
struct point
{
char s[LEN];
int next[LEN];
}p[MAX];
inline int min(int a, int b)
{
return (a<b)?a:b;
}
int dp[LEN][LEN];
int cal_levenshtein(char *s1,char *s2)
{
int l1 = strlen(s1);
int l2 = strlen(s2);
dp[l1][l2] = 1000;
dp[0][0] = 0;
for(int i=1; i<=l1; i++)
dp[i][0] = i;
for(int i=1; i<=l2; i++)
dp[0][i] = i;
for(int i=1; i<=l1; i++)
for(int j=1; j<=l2; j++)
if(s1[i-1]!=s2[j-1])
dp[i][j] = min(min(dp[i-1][j-1]+1,dp[i-1][j]+1),dp[i][j-1]+1);
else dp[i][j] = min(min(dp[i-1][j-1],dp[i-1][j]+1),dp[i][j-1]+1);
return dp[l1][l2];
}
int cnt = 0;
void insert(char *s,int x)
{
int tmp = cal_levenshtein(s,p[x].s);
if(p[x].next[tmp]==-1)
{
p[x].next[tmp] = ++cnt;
memset(p[cnt].next,-1,sizeof(p[cnt].next));
strcpy(p[cnt].s,s);
return;
}
insert(s,p[x].next[tmp]);
}
int query(char *s,int c,int x)
{
int ans = 0;
int tmp = cal_levenshtein(s,p[x].s);
if(tmp<=c) ans++;
int i,end;
if(tmp-c<0) i = 0;
else i = tmp-c;
if(tmp+c>LEN) end = LEN;
else end = tmp+c;
for(;i<=end; i++)
if(p[x].next[i]!=-1)
ans+=query(s,c,p[x].next[i]);
return ans;
}
int main()
{
int cas;
scanf("%d",&cas);
for(int t=1; t<=cas; t++)
{
int n,m;
scanf("%d%d",&n,&m);
scanf("%s",p[0].s);
memset(p[0].next,-1,sizeof(p[0].next));
cnt = 0;
char s[LEN];
for(int i=1; i<n; i++)
{
char s[LEN];
scanf("%s",s);
insert(s,0);
}
printf("Case #%d:\n",t);
while(m--)
{
int c;
scanf("%s%d",s,&c);
printf("%d\n",query(s,c,0));
}
}
return 0;
}


再附上自己的暴力代码:
#include <cstdio>
#include <cstring>
char s[1510][15];
char s2[15];
int dp[15][15];
int len[1510];
int n,m,l;
inline int min(int a,int b)
{
return (a<b)?a:b;
}
int cal(int x)
{
int cnt = 0,j,k;
l = strlen(s2);
for(int i=0; i<n; i++)
{
if(l-len[i]>x||l-len[i]<-x)
continue;
dp[0][0] = 0;
for(j=0; s[i][j]; j++)
dp[j+1][0] = j+1;
for(j=0; s2[j]; j++)
dp[0][j+1] = j+1;
for(j=0;s[i][j]; j++)
for(k=0; s2[k]; k++)
if(s[i][j]!=s2[k])
dp[j+1][k+1] = min(min(dp[j][k]+1,dp[j][k+1]+1),dp[j+1][k]+1);
else dp[j+1][k+1] = min(min(dp[j][k],dp[j][k+1]+1),dp[j+1][k]+1);
if(dp[j][k]<=x) cnt++;
}
return cnt;
}
int main()
{
int cas,x;
scanf("%d",&cas);
for(int t=1; t<=cas; t++)
{
scanf("%d%d",&n,&m);
for(int i=0; i<n; i++)
{
scanf("%s",s[i]);
len[i] = strlen(s[i]);
}
printf("Case #%d:\n",t);
while(m--)
{
scanf("%s%d",s2,&x);
printf("%d\n",cal(x));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: