您的位置:首页 > 其它

HDU-1298 | POJ-1451-T9

2012-08-12 10:15 501 查看

T9

HDU: http://acm.hdu.edu.cn/showproblem.php?pid=1298

POJ: http://poj.org/problem?id=1451



题目大意:手机上有0~9共十个数字按键,其中只有2到9有对应的英文字母,你要打一个单词,比如hello,那就要按键 4 共 两 次, 键 3 共 两 次, 键5 共 三 次,再按5键共三次,再按键6三次,为了减少按键数,开发商发明了一种新的规则叫 “ T9 ”,这个规则是根据单词的出现频率来实现单词的按键组合功能,比如,“hello" , "he", "hell" 的出现频率分别为 3, 4, 5, 那么字母 ‘h’ 出现的频率为 3 + 4
+ 5 =12,‘o'出现的频率为1. 那么在按 "hello" 的话,只需要按4,3,5,5,6,共五次就可以了,大大减少了按键次数,现要求你模拟这个规则,输出相应的单词,如果该单词不存在,则输出“MANUALLY”。

输入: 第一行 有一个整数表示 测试用例数

每一个用例 先有一个整数N(0~1000,包括0和1000),表示单词数, 接下来N行,每行有一个单词(长度最长为100)和一个频率数P(1—100),接着有一个整数M,表示要输入的按键数字。结尾为1,表示后面接有一个单词。

输出:对应每一个数字串,每按一个数字就输出相应的字符串,不存在则输出”MANUALLY“,否则输出频率最大的字符串,如果频率相同则按字典序输出最前的那一个。处理完一个数字串后,在后面再输出一行空行,每一个用例后也要有一个空行。

分析: 看完长长的一段题目,发现这是一道典型的字典树(tire tree)题,每按一个键,我们就要找出该数字键对应的字母所在的串,直到处理完这个数字序列。这个不难实现,基本上就是字典树的基本功能。

但我们从中分析出约束条件 1、输出对应的字符串 2、要求频率是最多的 3、字典序输出 4、格式控制(每一个数字串处理后要再输出额外的空行,每一个用例结束后也要有一个空行)。

要实现这些约束条件,按经验法则,先优先处理约束最强的那一个条件,字典序,为何是字典序是最难的呢?(其实也是最简单的)因为我们在从根往下找时,如果碰到相同的频率的词汇,就要比较哪一个字典序较靠前,因为树是非线性的,要进行比较实现比现困难,但我们发现,如果我们先碰到一个频率最大的,此时它的字典序也是最靠前的,因为按键上的字母也是按字典序来进行排序的,我们的查找也是按字典序来进行查找的,这样就避免了比较,直接查找频率最大的就行了。如图所示:



在输入”221”时,先处理第一个2,输出“c”,再处理第二个2时,输出"bc",不用再考虑“ca”了。另外,在要输出某个串时,我增加了一个额外的父指针,那么在某个结点要输出这个词汇时,回溯就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define MAX26
usingnamespace std;

int key_str[10][4]={
{-
1}, {-1},{0,1,2},
{
3,4,5},
{6,7,8},
{
9,10,11},
{
12,13,14},
{15,16,17,18},
{
19,20,21},
{
22,23,24,25}
};
int len_str[10]={
1, 1, 3,
3, 3, 3,
3, 4, 3,
4 };

struct tire
{
int degree,data;
struct tire *next[MAX],
*
father;
tire() //此构造函数只有用C++的new操作符才有效,malloc无效,否则使用malloc出错
{
for( int i=0;
i<MAX; i++ )next[i]=
NULL; degree=data=0,father=NULL;
}
};

int insert(char
*
str, struct tire *root, int
de )
{
int len = strlen(str
),
pos;
struct tire *read
=
root;

for( int i=0;
i<len; i++ )
{
pos = (int)(
str[i] - 'a' );

if( !read->next[pos]
)

read->next[pos]
= new struct
tire;

read->next[pos]->father
=
read; //记录父结点

read =read ->next[pos];
//移到下一个位置

read->data = pos;
read->degree+=de;
//所经过的字母的频率均要累加

}
return 0;
}

int PRINTF(struct
tire *root ) //打印词汇
{
if( !root )
return
0;
int str[110],len=0,i;
while( root->father
) //从结点向根结点走

{
str[len++]=root->data;
root=root->father;
}
for( i=len-1;
i>=0; i-- ) printf(
"%c",'a'+str[i] );
printf( "\n"
);

}

bool find( intx, struct
tire *root )
{
if( root ==
NULL || root->next[x] ==NULL
) return
false;
else return true;
}

int work( char
*
str, struct tire *root )
{
int len = strlen(str
),
pos,store_num, i, j,k,
record_store;
struct tire *read=NULL,
*
maxpriority=NULL;
queue<struct tire*>store;

store.push( root
);


for( i=0,store_num
=
1; i<len-1;
i++ ) //最外层表示按键顺序
{
maxpriority=NULL;
pos = (int)(
str[i] - '0' ); //按键数字

for( j=0,record_store=0;
j<store_num; j++ ) //查找到可能的单词数
{
read= store.front(); //取出起始查找位置
store.pop(); //退出队列

for( k=0;
k<len_str[pos]; k++ ) //每一个按键对应的多个字母
{
if( find(
key_str[pos][k] ,read ) ) //key_str表示按键pos对应多个字母的其中第k个字母
{
if( !maxpriority
)

maxpriority=
read->next[ key_str[pos][k]
];

else if( maxpriority
->degree <
read->next[key_str[pos][k]
] ->
degree )
{ //这里有点复杂,先是找到这个按键pos对应的第k个字母所代表的整数值,见代码初始段,如果是字母'b',那么值就为'b'-'a',然后在这个结点找它的儿子指针的频率
maxpriority = read->next[
key_str[pos][k] ];
}
store.push(read->next[
key_str[pos][k] ] );
record_store++;
}
}
}

if( record_store
==
0 ) {store_num=0;
printf( "MANUALLY\n" ); }
else
{
store_num = record_store;
PRINTF(maxpriority );
maxpriority=NULL;
}
}
}

int dealtire(struct
tire *root )
{
for( int i=0;
i<MAX; i++ )
{
if( root->next[i]
)
dealtire( root->next[i] );
}
delete root;
}

int main()
{
int t, word_num,press_num,
i, j,degree, s=0;
char word[110];

scanf( "%d",&t
);

while( t-- )
{
struct tire *root
= new struct
tire;
scanf( "%d",&word_num
);

for( i=0;
i<word_num;i++ )
{
scanf( "%s%d",word,
&
degree );
insert(word, root,degree
);

}

printf( "Scenario #%d:\n",
++
s );
scanf( "%d",&press_num
);

for( i=0;
i<press_num;i++ )
{
scanf( "%s",word
);


work(word, root);
printf( "\n"
);

}
printf("\n");
dealtire(root );
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: