这道题我做了三次,调了三次,加起来有好几天的时间,一直没有做对,今天又研究了一天,终于在晚上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数组计算每一个按键上的字母索引范围,最后就可以打印出来了。
希望对大家有所帮助,欢迎留言交流!