[51nod1373]哈利与他的机械键盘
作为一名屌丝程序员,机械键盘是哈利梦寐以求的神器。终于,在除夕夜的时候,他爸爸送了他一个机械键盘。
哈利的键盘与我们平常所见到的的键盘不一样,我们可以认为他的键盘是一个500*500的矩形,其中26个字母键分布在某些格点上。这天,心血来潮的哈利想用他心爱的键盘写一些代码,假设他的代码只有一行,而且都是由小写的英文字母构成。由于键盘上的按键分布在不同的地方,哈利码代码时,移动手指要花费一些能量,其花费能量为上一次敲击的键,与当前要敲的键的曼哈顿距离。为了节省力气,哈利可以不必完全按照要敲的代码输入,他可以跳着输,比如helloworld,他可以按照d r o o l l l e h w的顺序输入,但是为了让输入的代码是他想要的输入顺序,在输入的过程中,他可能需要移动光标,在相应的位置输入对应的单词,作为一名熟练的vim选手,哈利将光标移动一个位置仅需1的费用,比如他想输入qpy,他按q->y->p的顺序输入,那么花费的总的能量为cost(q,y)+1+cost(y,p),其中cost(x,y)为字母x,y之间的曼哈顿距离,当中花费的1的能量为输入y后,往左移动一次光标所花费的能量。当然,人的记忆力都是有限的,哈利最多只能记住连续10个位置的字母有没有输入过,也就是说如果想输入第i个字符,要么i<=10或者所有第i-10(包含)以前的字符都已经输入,比如第1个位置的字母还没有输,他就不能考虑第11个字母,因为一旦考虑第11个字母的时候,他就忘了第1个字母有没有输了。现在哈利想知道,他敲完这篇代码,最少需要多少能量?哈利第一次输入的时候可以不花费能量。
Input
前26行,每行两个整数x, y (0<=x<500, 0<=y<500)以空格分开,表示26个英文字母键a-z所在位置,保证不会有两个键在相同的位置
第27行为一个长度不超过100的字符串(非空),表示哈利要敲的代码,由小写字母a-z组成
Output
输出一个整数,表示哈利敲完代码最少花多少能量
状压DP。f[i][j][zt]表示考虑了前i位(i-10以前的都填完了),在最后10位里的第j位,最后10位里是否填了数的状态为zt。
转移的话,一种是从j挪到最后10位里的另外一个未填的位,另一种是从j挪到第i+x位,要求x<=10且i-10..i-10+x都填了。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #define ll long long 7 #define ui unsigned int 8 #define ull unsigned long long 9 const int maxn=100233,inf=1002333333; 10 int f[102][10][1233]; 11 int dis[1233][10][11],map[29][29],x[29],y[29]; 12 int i,j,k,n,m; 13 char s[123],s1[123]; 14 15 int ra,fh;char rx; 16 inline int read(){ 17 rx=getchar(),ra=0,fh=1; 18 while((rx<'0'||rx>'9')&&rx!='-')rx=getchar(); 19 if(rx=='-')fh=-1,rx=getchar(); 20 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh; 21 } 22 23 inline void mins(int &a,int b){if(b<a)a=b;} 24 inline int run(int n){ 25 int i,j,_j,zt;register int j1,_j1,zt1;int mx=1<<10,nowf; 26 // for(i=1;i<=n;i++)printf("%c",s[i]+'a'-1);puts(""); 27 for(i=10;i<=n;i++)memset(f[i],60,sizeof(f[i])); 28 for(i=0;i<10;i++)f[10][i][1<<i]=0; 29 30 for(i=10;i<=n;i++)for(zt=1;zt<mx;zt++)for(j=0,_j=i-9+j;j<10;j++,_j++)if(zt&(1<<j)){ 31 nowf=f[i][j][zt]; 32 for(j1=0,_j1=i-9+j1;j1<10;j1++,_j1++)if(!(zt&(1<<j1))) 33 mins(f[i][j1][zt|(1<<j1)],nowf+map[s[_j]][s[_j1]]+dis[zt][j][j1]); 34 for(j1=0,_j1=i+1+j1,zt1=zt>>1;j1<10&&(zt&(1<<j1))&&_j1<=n;j1++,_j1++,zt1>>=1) 35 mins(f[_j1][9][zt1|(1<<9)],nowf+map[s[_j]][s[_j1]]+dis[zt][j][10]); 36 } 37 int ans=1<<30; 38 for(i=0;i<10;i++)mins(ans,f[n][i][mx-1]); 39 // printf(" %d\n",ans); 40 return ans; 41 } 42 inline int abs(int x){return x<0?-x:x;} 43 int main(){ 44 int mx=1<<10; 45 for(i=0;i<mx;i++)for(j=0;j<10;j++)if(i&(1<<j))for(k=0;k<11;k++)if(!(i&(1<<k))){ 46 int a=j,b=k;if(a>b)std::swap(a,b); 47 for(int i1=a+1;i1<b;i1++)if(i&(1<<i1))dis[i][j][k]++; 48 dis[i][j][k]+=k<j; 49 } 50 51 for(i=1;i<=26;i++){ 52 x[i]=read(),y[i]=read(); 53 for(j=1;j<=i;j++)map[i][j]=map[j][i]=abs(x[i]-x[j])+abs(y[i]-y[j]); 54 } 55 scanf("%s",s+1),n=strlen(s+1); 56 for(i=1;i<=n;i++)s[i]-='a'-1; 57 58 if(n>=10)return printf("%d\n",run(n)),0; 59 for(i=1;i<=n;i++)s1[i+10-n]=s[i]; 60 int ans=1<<30; 61 for(i=1;i<=26;i++){ 62 for(j=1;j<=10-n;j++)s1[j]=i; 63 memcpy(s,s1,sizeof(s1)); 64 mins(ans,run(10)); 65 } 66 printf("%d\n",ans); 67 }