这道题我做了三次,调了三次,加起来有好几天的时间,一直没有做对,今天又研究了一天,终于在晚上21:44分AC了,痛苦之后很痛快!所以写一篇文章记录一下解决过程,也希望对大家有所帮助。
先上代码:
//============================================================================ // Name : testCPP.cpp // Author : jiadebin // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <fstream> using namespace std; #define MAX 90 #define INF 99999999 #define LOOPWB(i, b, j) for(i=(b); i<=(j); i++) int main() { char key[MAX], letter[MAX]; int cost[MAX][MAX], lkcost[MAX][MAX], pre[MAX][MAX], next[MAX], fre[MAX]; int m, n, t, it; int k, i, j; string filename("D:\\C&C++workspace\\testCPP\\src\\data.txt"); ifstream in(filename.c_str()); if(!in){ cout<<"error!\n"; return 1; } // cin>>t; in>>t; for(it=0; it<t; it++){ in>>m>>n; // cin>>m>>n; LOOPWB(i, 0, m-1){ in>>key[i]; // cin>>key[i]; } LOOPWB(i, 0, n-1){ // cin>>letter[i]; in>>letter[i]; } LOOPWB(i, 0, n-1){ // cin>>fre[i]; in>>fre[i]; } LOOPWB(i, 0, n-1){ lkcost[i][i]=fre[i]; LOOPWB(j, i+1, n-1){ lkcost[i][j]=lkcost[i][j-1]+(j-i+1)*fre[j]; } } LOOPWB(i, 0, n-1){ cost[0][i]=lkcost[0][i]; pre[0][i]=0; } LOOPWB(i, 1, m-1){ //按键循环变量i,表示有i+1个按键 LOOPWB(j, i, n-1){ //字母循环变量j,表示有j+1个字母 cost[i][j]=INF; //先把对应代价设为无穷 LOOPWB(k, i-1, j-1){ //前i-1个按键里的字母数,从i个变化到j个,寻找最优点 if(cost[i][j]>cost[i-1][k]+lkcost[k+1][j]){ cost[i][j]=cost[i-1][k]+lkcost[k+1][j]; pre[i][j]=k+1; //记录最优点处,前i个按键一共有k+1个字母 } } } } next[m-1]=n; //最优点处,第m个按键上最后一个字母的编号,即该按键上编号最大的字母 for(j=m-2, i=pre[m-1][n-1]; j>=0; j--){ next[j]=i; i=pre[j][i-1]; } printf("Keypad #%d:\n", (it+1)); for(i=0,j=0; j<=n&&i<m; j=next[i], i++){ cout<<key[i]<<": "; LOOPWB(k, j, (next[i]-1)){ cout<<letter[k]; } cout<<endl; } cout<<endl; //不加这个换行无法通过,提示结果显示错误,因为要求每个case之后加一个空行 } return 0; }
题目我就不解释了,大家可以去http://acm.hit.edu.cn/hoj/problem/view?id=1042 看,大致就是我们手机键盘上的字母安排问题,每个按键分配多少个字母可以使总的输入速度最快(即点击次数最少),这是一道动态规划题,我们首先定义一个数组lkcost[i][j]存储的是,第i至j个字母在同一个按键上时的总代价(j>i),这个二维数组的作用是方便后边计算cost[i][j]的值,cost[i][j]才是我们用来存储当有i个按键j个字母时的最优代价。
首先写出递推方程,经过分析可以得出,cost[i][j]的计算需要考虑前(i-1)个按键上有多少个字母最合适,所以我们需要遍历这些情况,选出总代价最小的k值,其中k代表前i-1个按键上总共的字母数。这就是主要的思想。所以递推方程是:
cost[i][j]= Min { cost[i-1][k]+lkcost[k+1][j]) , i-1<=k<=j-1 }
由于最后需要显示出每个按键上的字母,所以在求最优代价的过程中,还要记录每一个k值,代码中我用数组P保存相应位置的k值,然后根据P数组计算每一个按键上的字母索引范围,最后就可以打印出来了。
希望对大家有所帮助,欢迎留言交流!