[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 }
View Code

 

posted @ 2016-10-11 21:59  czllgzmzl  阅读(198)  评论(0编辑  收藏  举报