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;
}
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;
}
相关文章推荐
- 2017 多校训练第三场 HDU 6063 RXD and math
- 2017 多校训练第三场 HDU 6066 RXD's date
- 2017 多校训练第三场 HDU 6060 RXD and dividing
- (2017多校训练第三场)HDU - 6058 Kanade's sum 链表
- (2017多校训练第三场)HDU - 6063 RXD and math 找规律 + 快速幂
- 2017 多校训练第三场 HDU 6058 Kanade's sum
- HDU 4864 Task (2014多校联合训练第一场1004) 解题报告(贪心)
- 多校第三场:hdu(4323:编辑距离算法)
- hdu 4888 2014多校第三场1002 Redraw Beautiful Drawings 网络流
- hdu 4891 The Great Pan 2014多校联合第三场
- HDU 4643 GSM 暑期多校联合训练第五场 1001
- hdu 6088 Rikka with Rock-paper-scissors (2017 多校第五场 1004) 【组合数学 + 数论 + 模意义下的FFT】
- (HDU 5775)Bubble Sort <树状数组> 多校训练4
- 2017 多校训练第二场 HDU 6052 To my boyfriend
- hdu 4911 Inversion(归并排序求逆序对数)2014多校训练第5场
- hdu 4970 Killing Monsters(数组的巧妙运用) 2014多校训练第9场
- hdu 5319 Painter (2015多校第三场第4题)暴力模拟(瞎搞)
- HDU 4669 Mutiples on a circle (2013多校联合7 1004)
- hdu 4325 Flowers 2012多校1006题 树状数组解法
- (2017多校训练第七场)HDU - 6127 Hard challenge 极角排序+尺取法