题目

给定一个 n*m 的矩阵 A ,矩阵中每一个元素为一个十六进制数。寻找一条从左上角都右下角的路径,每次只能向右或者向下移动, 
使得路径上所有数字之积在 16 进制下的后缀 0 最少。

输入描述:

第一行:n, m (2 <= n,m <= 1000) 
接下来 n 行,每行 m 个 16 进制整数 0<=aij<=1090<=aij<=109

输出描述:

第一行:最少后缀 0 的个数(十进制) 
第二行:路径方案,从左上角开始,”>” 代表向右移动,”V” 代表向下移动。 
如果有多种方案,输出字典序最小的方案(“>” 的字典序小于 “V”)。

示例:
  • 输入

    3 3 
    3 2 8 
    c 8 8 
    2 a f

  • 输出


    ‘>>VV’(此处输出实际上没有引号)

  • 说明 
    从左上角到右下角的所有路径中, 0x3 * 0x2 * 0x8 * 0x8 * 0xf = 0x1680 后缀 0 最少为 1, 且路径 “>>VV” 的字典序最小。

思路

  • 首先需要设计一个函数来判断十六进制数字末尾零的个数。可以分为两种情况,小于 16 的数只有 0 末尾有一个零;大于等于 16 的数如果最后一位是 0,则肯定可以被 16 整除,若末尾是 0,我们对这个十六进制数向右移一位,也即除以 16,再看倒数第二位是否是零,这样一直往前判断直到某一位非零为止。

  • 路径判断则用动态规划来实现。定义两个变量,第一个变量保存从左上角到每一个位置处的乘积,第二个变量保存是怎样从前一步到当前位置的,只有向右或者向下两种情况,用枚举表示。第一行只能向右走,第一列只能向下走,这是初始化情况。然后从第二行第二列开始进行判断,每一步比较从左边来的乘积和从上边来的乘积末尾含有零的个数,若二者不相等,则保存乘积和移动方向到相应变量中。若向下和向右二者相等,则需要分别向上和向左回溯到左上角倒序求出移动方向,然后从头开始比较,选择字典序小的路径作为最终的移动方向。

样例展示 (从左到右分别是原始数字、十六进制乘积和移动方向)

3 o 2 (6) (>) 8 (30) (>)
c (24) (V) 8 (30) (V) 8 (180) (V)
2 (48) (V) a (1E0) (V) f (1680) (V)

第二行第二个位置,从左边来是 24×8 = 120,末尾有 1 个 0;从上边来是 6×8 = 30,也有 1 个 0。 
从左边来路径是 V>,从右边来路径是 >V,由于 > 字典序小于 V,因此最终移动方向为 >V。

代码实现

#include <iostream>
#include <vector>
using namespace std; int find_zero_num(int number);
int min_dictionary(int *direction, int i, int j, int col);
void find_route(int *direction, vector<int> &route, int m, int n, int col); enum {RIGHT = , DOWN = }; //向下走为 1 ,向右走为 0 int main()
{
int n = , m = ;
cin >> n >> m; int data[n][m];
//保存矩阵中的数据
long int product[n][m];
//保存从左上角到位置(i, j)处的乘积
int direction[n][m] = {};
//保存位置(i, j)处的乘积是怎么得到的,1为从前一位置往下,0为从前一位置往右 vector<int> route; //倒序保存路径 int i = , j = ; for(i = ; i < n ; i++)
{
for(j = ; j < m; j++)
{
cin >> hex >> data[i][j];
}
} // 初始化第一列的乘积作为边界值
product[][] = data[][];
for(i = ; i < n; i++)
{
product[i][] = product[i-][] * data[i][];
direction[i][] = DOWN;
} // 初始化第一行的乘积作为边界值
for(j = ; j < m; j++)
{
product[][j] = product[][j-] * data[][j];
direction[][j] = RIGHT;
} long int down = ;
long int right = ;
int flag = ; for(i = ; i < n; i++)
{
for (j = ; j < m; j++)
{
down = product[i-][j] * data[i][j]; //往下走的乘积
right = product[i][j-] * data[i][j]; //往右走的乘积 if (find_zero_num(down) < find_zero_num(right))
{
flag = ;
}
else if (find_zero_num(down) > find_zero_num(right))
{
flag = RIGHT;
}
else //若向下和向右一样,则优先取字典序小的
{
if(min_dictionary(*direction, i, j, m))
{
flag = DOWN;
}
else
{
flag = RIGHT;
}
} if(!flag)
{
product[i][j] = right;
direction[i][j] = RIGHT;
}
else
{
product[i][j] = down;
direction[i][j] = DOWN;
}
}
} cout << find_zero_num(product[n-][m-]) << endl; find_route(*direction, route, n-, m-, m); for(i = int(route.size()-); i >= ; i--)
{
if (route[i])
{
cout << 'V';
}
else
{
cout << '>';
}
} return ;
} // find the zero number of a hex data
int find_zero_num(int number)
{
int sum = ;
if(number == )
{
sum = ;
}
while (number % == && number >= )
{
sum++;
number = number / ;
}
return sum;
} int min_dictionary(int *direction, int i, int j, int col)
{
vector<int> route_down;
vector<int> route_right; int m = i - ;
int n = j;
find_route(direction, route_down, m, n, col); //向上回溯路线 m = i;
n = j - ;
find_route(direction, route_right, m, n, col); //向左回溯路线 int length = int(route_right.size()); for (i = length - ; i >= ; i--) //从第一个不相等的位置处开始判断字典序
{
if (route_right[i] < route_down[i])
{
return ; //向右字典序小
}
if (route_right[i] > route_down[i])
{
return ; //向下字典序小
}
} return -;
} // 从位置 (m, n) 处回溯路线,倒序保存在向量中
void find_route(int *direction, vector<int> &route, int m, int n, int col)
{
while()
{
// 此位置乘积由上一位置向下移动得来,行数减一继续寻找
if(direction[m * col + n] == )
{
m = m - ;
route.push_back();
}
// 此位置乘积由上一位置向右移动得来,列数减一继续寻找
else
{
n = n - ;
route.push_back();
} // 寻找至左上角,结束
if (m == && n == )
{
break;
}
}
}

个人见解,如有错误,欢迎指正与交流!

获取更多精彩,请关注「seniusen」! 

今日头条 2018 AI Camp 5 月 26 日在线笔试编程题第一道——最佳路径的更多相关文章

  1. 今日头条 2018 AI Camp 5 月 26 日在线笔试编程题第二道——最小分割分数

    题目: 给 n 个正整数 a_1,…,a_n, 将 n 个数顺序排成一列后分割成 m 段,每一段的分数被记为这段内所有数的和,该次分割的分数被记为 m 段分数的最大值.问所有分割方案中分割分数的最小值 ...

  2. 今日头条 2018 AI Camp 6 月 2 日在线笔试编程题第一道——最大连续区间和扩展

    题目 给出一个长度为 n 的数组a1.a2.....ana1.a2.....an,请找出在所有连续区间 中,区间和最大同时这个区间 0 的个数小于等于 3 个,输出这个区间和. 输入描述: 第一行一个 ...

  3. 今日头条 2018 AI Camp 6 月 2 日在线笔试编程题第二道——两数差的和

    题目 给 n 个实数 a_1, a_2 ... a_n, 要求计算这 n 个数两两之间差的绝对值下取整后的和是多少. 输入描述 第一行为一个正整数 n 和一个整数 m.接下来 n 行,第 i 行代表一 ...

  4. 今日头条 2018 AI Camp 视频面试

    1. 本次面试是在牛客网平台进行的,没有涉及到技术细节,面试官也说仅仅是聊天.但是,不知道是网络卡顿还是平台缘故,连接非常不稳定,经常听不到声音,对方那边噪音也特别大,面试体验不是很好. 2. 面试时 ...

  5. 链家2018春招C/C++开发实习生在线考试编程题

    题目一 题解:该题目意思就是让你输入n组数据,然后求并集,利用STL容器set集合的特性:元素不重复存储,我们可以很轻易得出答案 #include <iostream> #include ...

  6. [转帖]ARM A77+G77最强公版架构:联发科5G SoC计划11月26日发布

    ARM A77+G77最强公版架构:联发科5G SoC计划11月26日发布 https://www.cnbeta.com/articles/tech/909025.htm 主流的手机SoC厂商已经纷纷 ...

  7. 2016年12月26日 星期一 --出埃及记 Exodus 21:21

    2016年12月26日 星期一 --出埃及记 Exodus 21:21 but he is not to be punished if the slave gets up after a day or ...

  8. 10月26日 奥威Power-BI基于微软示例库(MSOLAP)快速制作管理驾驶舱 腾讯课堂开课啦

    本次课是基于olap数据源的案例实操课,以微软olap示例库Adventure Works为数据基础.        AdventureWorks示例数据库为一家虚拟公司的数据,公司背景为大型跨国生产 ...

  9. 2016年11月26日 星期六 --出埃及记 Exodus 20:17

    2016年11月26日 星期六 --出埃及记 Exodus 20:17 "You shall not covet your neighbor's house. You shall not c ...

随机推荐

  1. unittest单元测试框架之unittest 框架的总结(七)

    1. Unittest 是 python 自带的单元测试框架,可以用其作为自动化框架来组织测试用例(测 试用例的执行顺序)的执行. 2. Unittest 框架的流程: 写好 TestCase 通过 ...

  2. oracle使用DBMS_RANDOM包生成随机数据

    (一)DBMS_RANDOM包信息 DBMS_RANDOM包包含3个存储过程,4个函数,1个类型,一共8个模块,如下. SQL> desc dbms_random Element Type -- ...

  3. react组件间传值详解

    一.父子组件间传值     <1>父传子         父组件:

  4. django创建第一个django项目-2

    安装django 虚拟环境下执行命令: pip install django==1.11.11 查看是否安装成功 pip list 列表中有django说明安装成功 创建工程 命令行移动到想要创建项目 ...

  5. 『Linux基础 - 4 』linux常用命令(1)

    这篇笔记包含以下知识点: 几个概念的理解:Linux命令,控制台,终端, 终端提示符 对文件目录的操作的相关命令: 切换目录,列出目录下的文件等 对文件的操作的相关命令: 创建,删除,复制,修改,移动 ...

  6. 『Linux基础 - 2 』操作系统,Linux背景知识和Ubuntu操作系统安装

    这篇笔记记录了以下几个知识点: 1.目前常见的操作系统及分类,虚拟机 2.Linux操作系统背景知识,Windows和Linux两个操作系统的对比 3.在虚拟机中安装Ubuntu系统的详细步骤 OS( ...

  7. SQL盲注

    一.首先输入1和-1 查看输入正确和不正确两种情况 二.三种注入POC LOW等级 ... where user_id =$id 输入      真  and  假 = 假 (1)...where u ...

  8. 最小化的测试套件minimal_test的使用

    1:需要包含文件文#include <boost/test/minimal_test.hpp> 2:minimal_test内部实现了main(), 因此无需自己编写main()函数, 只 ...

  9. SVN的使用——下载、安装

    今天我们来学习一下如何使用SVN(Subversion) 既然要使用SVN那么我们就先来认识一下SVN.SVN的全名是Subversion,它是一个自由,开源的版本控制系统.在Subversion管理 ...

  10. P1011 车站

    P1011 车站 题目描述 火车从始发站(称为第1站)开出,在始发站上车的人数为a,然后到达第2站,在第2站有人上.下车,但上.下车的人数相同,因此在第2站开出时(即在到达第3站之前)车上的人数保持为 ...