题目

给定一个 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. CSS 高级选择器

    相信各位如我一样的“抠图崽”和前端大佬们,在写网页样式的实话,总是免不了写下各种各样的选择器,再给选择的元素写入样式.最基本的元素选择器.class选择器.ID选择器等就不再过多的说了,相信大家都熟的 ...

  2. mysql获取正在运行的sql

    select id,db,host,time,info,command from information_schema.processlist where command<>'sleep' ...

  3. 一点一点看JDK源码(二)java.util.List

    一点一点看JDK源码(二)java.util.List liuyuhang原创,未经允许进制转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.综述 List译为表,一览表, ...

  4. 【淘宝客】PHPMailer-v6.0.5版 发送邮件dome

    话不多说,根据官方dome修改下,官方更新地址:https://github.com/PHPMailer/PHPMailer <?php use PHPMailer\PHPMailer\PHPM ...

  5. curl下载文件

    * curl下载文件* 根据业务需求* 通过不同站点去访问路径* 下载文件* 但是不同站点需要设置header头* 这里使用curl方式下载* 具体看代码: //下载地址 $url = 'https: ...

  6. 四则运算_EX

    在原有四则运算基础上,除整数以外要支持真分数运算(验证正确性) 一次出的题避免相互重复 可定制出题数目 #include <stdio.h>#include <stdlib.h> ...

  7. 成都优步uber司机第三组奖励政策

    今天成都优步又推出了优步司机第三组,第一二组的奖励大家都晓得,但是第三组的奖励怎么样呢?还是先看看官方给出的消息. 滴滴快车单单2.5倍,注册地址:http://www.udache.com/如何注册 ...

  8. 成都Uber优步司机奖励政策(2月18日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  9. <简明>Markdown指南

    什么是Markdown?Markdown是一种轻量级的「标记语言」,通常为程序员群体所用,目前它已是全球最大的技术分享网站 GitHub 和技术问答网站 StackOverFlow 的御用书写格式. ...

  10. Linux下安装Nginx并实现socket代理

    nginx可以使用各平台的默认包来安装,本文是介绍使用源码编译安装,包括具体的编译参数信息. 正式开始前,编译环境gcc g++ 开发库之类的需要提前装好,这里默认你已经装好. ububtu平台编译环 ...