USACO 5.4.3 Character Recognition
题目大意(转自NOCOW,有缩减):
这个问题需要你写一个程序完成字符识别的任务。
每个完整的字符图案有 20 行,20 位。每个位是“0”或“1”
文件 font.in 包括了27个字符图案的信息,以这样的顺序记录:
_abcdefghijklmn
其中 _ 表示空格字符。每个完整字符长 20 行。输入文件包含一个或多个可能损坏的字符图案。一个字符图案可能以这些方式被损坏。
- 最多有一行可能被复制了(就接在原来那一行的下面)
- 最多有一行可能丢失了
- 有些“0”可能被改成“1”
- 有些“1”可能被改成“0”
不会有任何一个字符图案既多余了一行并且又丢失了一行。
被复制的那一行中,原来的行和多余的行可能都损坏了,而且损坏的部分可能并不相同。
写一个程序,使用 font.in 提供的字体,在输入文件提供的图象中识别出一个或多个的字符序列。
使用提供的字体图象来识别字符的时候,要找出最佳的多余行或遗漏行,使找出的所有“0”和“1”的变化数量最小。在所有可能的多余行中,只按损坏数据最少的那一行计算。你必须确定和输入序列最接近的字符序列(就是损坏数据最少的那一个)。每个测试数据有唯一的最优解。
简单题解(参考NOCOW):
本题暴力模拟应该是可以过的(USACO的传统)。
在暴力模拟的基础上,保存一些信息,可以加快速度。
保存信息1:dif[i][j][k],表示图案第i行与第j个字符第j行的差距。
保存信息2:cost[i][j],表示图案第i行开始的19+j行最小的匹配差距。
进一步,使用动态规划来求最优解。
令f[i]表示匹配到第i行为止可以取得的最小差距。
边界:f[0]=0,f[1~18]=INF。
转移:f[i]=min{f[i-19]+cost[i-18][0],f[i-20]+cost[i-19][1],f[i-21]+cost[i-20][2]}。
记录下取最优时对应的字符,输出即可。
我的代码:
1 /* 2 ID:t-x.h1 3 LANG:C++ 4 TASK:charrec 5 */ 6 #include<cstdio> 7 FILE *ff=fopen("font.in","r"),*fi=fopen("charrec.in","r"),*fo=fopen("charrec.out","w"); 8 const char ch[]="- abcdefghijklmnopqrstuvwxyz"; 9 const int MAXnf=27+9,N=20,MAXn=1200+9,INF=99999999; 10 char font[MAXnf][N][N],line[MAXn][N]; 11 int dif[MAXn][MAXnf][N],cost[MAXn][3],from[MAXn][3]; 12 int f[MAXn],g[MAXn],ans[99]; 13 int main() 14 { 15 int n,i,j,k,t; 16 fscanf(ff,"%*d\n"); 17 for(i=1;i<=27;++i) 18 for(j=1;j<=N;++j,fscanf(ff,"\n")) 19 for(k=1;k<=N;++k) 20 font[i][j][k]=fgetc(ff); 21 fscanf(fi,"%d\n",&n); 22 for(i=1;i<=n;++i,fscanf(fi,"\n")) 23 { 24 for(j=1;j<=N;++j) 25 line[i][j]=fgetc(fi); 26 for(j=1;j<=27;++j) 27 for(k=1;k<=N;++k) 28 for(t=1;t<=N;++t) 29 if(line[i][t]!=font[j][k][t]) 30 ++dif[i][j][k]; 31 } 32 for(i=1;i+18<=n;++i) 33 { 34 cost[i][0]=cost[i][1]=cost[i][2]=INF; 35 for(j=1;j<=27;++j) 36 { 37 t=0; 38 for(k=1;k<N;++k) 39 t+=dif[i+k-1][j][k]; 40 if(t<cost[i][0]) 41 cost[i][0]=t,from[i][0]=j; 42 for(k=19;k;--k) 43 { 44 t-=dif[i+k-1][j][k],t+=dif[i+k-1][j][k+1]; 45 if(t<cost[i][0]) 46 cost[i][0]=t,from[i][0]=j; 47 } 48 } 49 if(i+19<=n) 50 for(j=1;j<=27;++j) 51 { 52 t=0; 53 for(k=1;k<=N;++k) 54 t+=dif[i+k-1][j][k]; 55 if(t<cost[i][1]) 56 cost[i][1]=t,from[i][1]=j; 57 } 58 if(i+20<=n) 59 for(j=1;j<=27;++j) 60 { 61 t=0; 62 for(k=1;k<=N;++k) 63 t+=dif[i+k-1][j][k]; 64 if(t<cost[i][2]) 65 cost[i][2]=t,from[i][2]=j; 66 for(k=N;k;--k) 67 { 68 t-=dif[i+k-1][j][k],t+=dif[i+k][j][k]; 69 if(t<cost[i][2]) 70 cost[i][2]=t,from[i][2]=j; 71 } 72 } 73 } 74 for(i=1;i<=n;++i) 75 f[i]=INF; 76 for(i=19;i<=n;++i) 77 { 78 if(f[i-19]+cost[i-18][0]<f[i]) 79 f[i]=f[i-19]+cost[i-18][0],g[i]=19; 80 if(i>=20 && f[i-20]+cost[i-19][1]<f[i]) 81 f[i]=f[i-20]+cost[i-19][1],g[i]=20; 82 if(i>=21 && f[i-21]+cost[i-20][2]<f[i]) 83 f[i]=f[i-21]+cost[i-20][2],g[i]=21; 84 } 85 t=0; 86 for(i=n;i;i-=g[i]) 87 ans[++t]=from[i-g[i]+1][g[i]-19]; 88 for(i=t;i;--i) 89 fputc(ch[ans[i]],fo); 90 fputc(10,fo); 91 fclose(fi); 92 fclose(fo); 93 return 0; 94 }