您的位置:首页 > 其它

ACM解题总结——HihoCoder1153

2016-02-20 14:44 351 查看
题目来源:

        HihoCoder 1153
题目要求:
    以下是常见的手机数字键盘的排列方式:
                    1 2 3 
                    4 5 6
                    7 8 9
                      0
    开始状态下,你的手指的在按键1的位置。可以执行的操作有:按下手指所在位置的按键,或者将手指向下移动到下一个按键,或者将手指一定到右边的下一个按键。而向左和向上移动是不允许的。
    要求给定一个数字K,在不限制操作次数的情况下,求出在这样的操作方式下,可以输出的不大于K的最大数字。

解答:
    这个题目比较简单。数据量比较小,所以用最朴素的深度优先搜索算法就可以得到结果。
    首先需要了解的是,当手指处于某一个位置时,它还可以移动到那些位置。这里可以利用可达矩阵得到这些信息。首先将题目中的键盘转化成一个有向图,如下:

     


    然后,就可以得到可达矩阵,如果从数字i可以到达数字j,那么矩阵中第i行,第j列数字为1,否则为0,可达矩阵(记为V)如下, 其中行、列的编号都是从0开始的:

1 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1
1 0 1 1 0 1 1 0 1 1
0 0 0 1 0 0 1 0 0 1
1 0 0 0 1 1 1 1 1 1
1 0 0 0 0 1 1 0 1 1
0 0 0 0 0 0 1 0 0 1
1 0 0 0 0 0 0 1 1 1
1 0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0 0 1
    然后,就可以进行搜索求解了。保证得到的结果最大,那么就要尽可能地使结果中的各个数位的数字和K接近。搜索从最高位开始。起始位置是1,由于1可以到达所有数字,因此结果的最高位数字就是K的最高位数字。

    在后续的搜索中,则需要枚举,设上一轮的搜索结果是s, 那么在本轮搜索过程中,参考矩阵V,枚举S可达的所有数字,依次代入,看是否有解,找到是的结果最大的解即可。伪代码如下:

            
boolean search(char* num, int depth, int last) {
for i = 9 →0 {
if(V[last][i] = 1 ) {
if(search(num, depth+1, i) {
return true;
}
}
}
}


    由于i是倒序枚举的,因此,第一个找到的合法的结果一定是最大的结果。

    但是,上面的代码还有一个问题,就是没有考虑到“不大于K”这个条件,并不是每一轮的递归都可以从9开始枚举,这里设定一个标记tag,记录在进行当前搜索前,前面的搜索的结果是否和数字K中的对应位置相同,如果相同,tag为0, 否则:tag为1。例如对于数字65435,当进行到第3轮递归时,如果结果的前两位也是65,此时tag为1,那么为了保证结果不大于K,第三轮的搜索只能从K的第三位数字4开始,依次枚举:3,2,1,0;如果前两轮的结果是64,此时tag是1,那么由于高位已经有数位小于K,因此无论枚举的数字是多少,结果都不会大于K,此时可以枚举0-9的所有数字。

    因此,修改代码如下,在搜索前,先检查标识tag的值,如果是0,就从K值的对应数位的数字开始搜索,如果是1,那么就从9开始搜索。而在搜索过程中,如果发现搜索的值小于K对应数位的值依然找不到合法结果,那么将tag置为1。例如某个数字的前几位是654...,当在第三轮的递归时发现第三位取4不可以得到合法的结果,那么这说明第三位只能取比4小的数字,也就说明,后面的数位可以取0-9的任意值,因此将tag置为1。

    伪代码如下:

         
boolean search(char* num, int depth, int last) {
if(tag = 0) {
start = num[depth];
} else {
start = 9;
}
for i = start →0 {
if(i < num[depth]) {
tag = 1;
}
if(V[last][i] = 1 ) {
if(search(num, depth+1, i) {
result[depth] = i;
return true;
}
}
}
}


最后搜索完毕后,输出result中存储的内容即可。

输入输出格式:
    输入:输入的第一行为一个数字T,代表有T组测试数据;接下来的T行,每一行为一个数字K。
    输出:对于每一组测试数据,输出一个值,代表可以得到的不大于K的最大值。

数据范围:
    1≤K≤10^500
    1≤T≤20

程序代码:

/****************************************************/
/* File        : hiho_week_85.cpp                   */
/* Author      : Zhang Yufei                        */
/* Date        : 2016-02-20                         */
/* Description : HihoCoder ACM program. (submit:g++)*/
/****************************************************/

/*
* Update log:
*		Create by Zhang Yufei in 2016-02-20.
*			Submit: AC.
*/

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

/*
* The visitable matrix. If there exist path from number i to j,
* the value is 1, or 0.
*/
int matrix[10][10] = {
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 1, 0, 1, 1, 0, 1, 1},
{0, 0, 0, 1, 0, 0, 1, 0, 0, 1},
{1, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 1, 1, 0, 1, 1},
{0, 0, 0, 0, 0, 0, 1, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
};

/*
* The input number.
*/
char K[550];

/*
* The length of input K.
*/
int length;

/*
* This is a tag, indicating if program can iterate from 9.
* If tag equals 1, program iterates starting from 9, or from num[depth].
*/
int tag;

/*
* Store the result to output.
*/
char result[550];

/*
* This function deals with one input case.
* Parameters:
*		None.
* Returns:
*		None.
*/
void function(void);

/*
* This function search the answer for one test case,
* using iterating method.
* Parameters:
*		@num: The number in input.
*		@depth: The depth of iterate, it also means the position of the number
*				to deal with.
*		@last: The last number deal with in the last iterating.
* Returns:
*		If program finds an answer, return 1, or 0.
*/
int search(char* num, int depth, int last);

/*
* The main program.
*/
int main(void) {
int T;
scanf("%d", &T);
for(int i = 0; i < T; i++)
function();

return 0;
}

/*
* This function deals with one input case.
* Parameters:
*		None.
* Returns:
*		None.
*/
void function(void) {

scanf("%s", K);
length = strlen(K);
tag = 0;
search(K, 0, 1);

printf("%s\n", result);
}

/*
* This function search the answer for one test case,
* using iterating method.
* Parameters:
*		@num: The number in input.
*		@depth: The depth of iterate, it also means the position of the number
*				to deal with.
*		@last: The last number deal with in the last iterating.
* Returns:
*		If program finds an answer, return 1, or 0.
*/
int search(char *num, int depth, int last) {
if(depth == length) {
result[depth] = '\0';
return 1;
}

int start;
if(tag == 0) {
start = num[depth] - 48;
} else {
start = 9;
}
for(int i = start; i >= 0; i--) {
if(matrix[last][i]) {
if(i < num[depth] - 48) {
tag = 1;
}
if(search(K, depth + 1, i)) {
result[depth] = i + 48;
return 1;
}
}
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm 微软笔试题