哈工大hoj第1042题,动态规划

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

         希望对大家有所帮助,欢迎留言交流!

       

你可能感兴趣的:(哈工大hoj第1042题,动态规划)