Hoj 1042 I-KeyBoard

Problem Description

Most of you have probably tried to type an SMS message on the keypad of a cellular phone. It is sometimes very annoying to write longer messages, because one key must be usually pressed several times to produce a single letter. It is due to a low number of keys on the keypad. Typical phone has twelve keys only (and maybe some other control keys that are not used for typing). Moreover, only eight keys are used for typing 26 letters of an English alphabet. The standard assignment of letters on the keypad is shown in the left picture:

 

1
 
2
abc
3
def
4
ghi
5
jkl
6
mno
7
pqrs
8
tuv
9
wxyz
*
 
0
space
#
 
      
1
 
2
abcd
3
efg
4
hijk
5
lm
6
nopq
7
rs
8
tuv
9
wxyz
*
 
0
space
#
 

There are 3 or 4 letters assigned to each key. If you want the first letter of any group, you press that key once. If you want the second letter, you have to press the key twice. For other letters, the key must be pressed three or four times. The authors of the keyboard did not try to optimise the layout for minimal number of keystrokes. Instead, they preferred the even distribution of letters among the keys. Unfortunately, some letters are more frequent than others. Some of these frequent letters are placed on the third or even fourth place on the standard keyboard. For example, S is a very common letter in an English alphabet, and we need four keystrokes to type it. If the assignment of characters was like in the right picture, the keyboard would be much more comfortable for typing average English texts.

ACM have decided to put an optimised version of the keyboard on its new cellular phone. Now they need a computer program that will find an optimal layout for the given letter frequency. We need to preserve alphabetical order of letters, because the user would be confused if the letters were mixed. But we can assign any number of letters to a single key.

Input

There is a single positive integer T on the first line of input. It stands for the number of test cases to follow. Each test case begins with a line containing two integers K, L (1 <= K <= L <= 90) separated by a single space. K is the number of keys, L is the number of letters to be mapped onto those keys. Then there are two lines. The first one contains exactly K characters each representing a name of one key. The second line contains exactly L characters representing names of letters of an alphabet. Keys and letters are represented by digits, letters (which are case-sensitive), or any punctuation characters (ASCII code between 33 and 126 inclusively). No two keys have the same character, no two letters are the same. However, the name of a letter can be used also as a name for a key.

After those two lines, there are exactly L lines each containing exactly one positive integer F1, F2, ... FL. These numbers determine the frequency of every letter, starting with the first one and continuing with the others sequentially. The higher number means the more common letter. No frequency will be higher than 100000.

Output

Find an optimal keyboard for each test case. Optimal keyboard is such that has the lowest "price" for typing average text. The price is determined as the sum of the prices of each letter. The price of a letter is a product of the letter frequency (Fi) and its position on the key. The order of letters cannot be changed, they must be grouped in the given order.

If there are more solutions with the same price, we will try to maximise the number of letters assigned to the last key, then to the one before the last one etc.

More formally, you are to find a sequence P1, P2, ... PL representing the position of every letter on a particular key. The sequence must meet following conditions:

  • P1 = 1
  • for each i>1, either Pi = Pi-1+1 or Pi = 1
  • there are at most K numbers Pi such that Pi = 1
  • the sum of products SP = Fi.Pi is minimal
  • for any other sequence Q meeting these criteria and with the same sum SQ = SP, there exists such M, 1 <= M <= L that for any J, M<J <= L, PJ = QJ, and PM>QM.

The output for every test case must start with a single line saying Keypad #I:, where I is a sequential order of the test case, starting with 1. Then there must be exactly K lines, each representing one letter, in the same order that was used in input. Each line must contain the character representing the key, a colon, one space and a list of letters assigned to that particular key. Letters are not separated from each other.

Print one blank line after each test case, including the last one.

Sample Input

1

8 26

23456789

ABCDEFGHIJKLMNOPQRSTUVWXYZ

3371

589

1575

1614

6212

971

773

1904

2989

123

209

1588

1513

2996

3269

1080

121

2726

3083

4368

1334

518

752

427

733

871

Sample Output

Keypad #1:

2: ABCD

3: EFG

4: HIJK

5: LM

6: NOPQ

7: RS

8: TUV

9: WXYZ

 

题意:给你一些按键和字母,以及每一个字母的使用频率,让你构造一种老式手机的键盘,假设一个字母在键盘中的位置为x,使用频率为p,那么他的贡献就是x*p  我们使每个字母的贡献和最小。

 

解题思路:我们构造两个数组f[i][j]表示我们用了i个按键,以第j个字母结尾的最小贡献。

g[i][j]表示在最小贡献的时候第i个按键的开始字母。

price(i,j)表示字符i到j连续排列到同一个按键上需要的贡献。

初始时f[1][n]=price(1,n)

状态转移方程:f[i][j]=min{f[i-1][k]+price(k+1,j) }  (i-1<=k<j)

 

/*************************************************************************
	> File Name: hoj1042.cpp
	> Author: baozi
	> Last modified: 2018年08月13日 星期一 13时21分
	> status:AC 
 ************************************************************************/
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=220;
#define mem(a,b) memset(a,b,sizeof(a)) 
int d[maxn],f[maxn][maxn],g[maxn][maxn],n,m;
char key[maxn],le[maxn];
int pri(int l,int r){
	int sum=0;
	for(int i=l;i<=r;i++){
		sum+=d[i]*(i-l+1);
	}
	return sum;
}
void prin(int l,int r){
	for(int i=l;i<=r;i++){
		printf("%c",le[i]);
	}
}
void find(int ke,int ll){
	if(ke>1) find(ke-1,g[ke][ll]);
	printf("%c: ",key[ke-1]);
	prin(g[ke][ll],ll-1);
	printf("\n");
}
int main(){
	int i,j,t,cas=1,k;
	scanf("%d",&t);
	for(cas=1;cas<=t;cas++){
		scanf("%d%d",&n,&m);
		scanf("%s%s",key,le);
		for(i=1;i<=m;i++) scanf("%d",&d[i]);
		mem(f,0);mem(g,0);
		for(i=1;i<=m;i++) f[1][i]=pri(1,i);
		for(i=2;i<=n;i++){
			for(j=1;j<=m;j++){
				f[i][j]=f[i-1][i-1]+pri(i,j);
				g[i][j]=i-1;
				for(k=i;k<j;k++){
					int s=f[i-1][k]+pri(k+1,j);
					if(f[i][j]>s){
						f[i][j]=s;
						g[i][j]=k;
					}
				}
			}
		}
		printf("Keypad #%d:\n",cas);
		find(n,m);
		printf("\n");
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值