问题链接:http://codeforces.com/contest/2/problem/B
有一个方阵矩阵n×n,由非负整数组成。你应该找到这样的方式
从矩阵的左上角开始; 每个后续单元格位于当前单元格的右侧或下方; 这种方式在右下方的细胞中结束。 而且,如果我们将所有数字相乘,结果应该是最小的“圆形”。换句话说,它应该以尽可能少的零结束。
输入 第一行包含整数n(2≤n≤1000),n是矩阵的大小。然后跟随包含矩阵元素的n行(非负整数不超过10 ^ 9)。
输出 在第一行中打印最少数量的尾随零。在第二行打印相应的方式本身。
我想到了以下内容:最后,无论答案是什么,它都应该包含2和5的最小功率。因此,我所做的是,对于输入矩阵中的每个条目,我计算了2和5的幂并将它们存储在单独的矩阵中。
for (i = 0; i < n; i++)
{
for ( j = 0; j < n; j++)
{
cin>>foo;
matrix[i][j] = foo;
int n1 = calctwo(foo); // calculates the number of 2's in factorisation of that number
int n2 = calcfive(foo); // calculates number of 5's
two[i][j] = n1;
five[i][j] = n2;
}
}
之后,我这样做了:
for (i = 0; i < n; i++)
{
for ( j = 0; j < n; j++ )
{
dp[i][j] = min(two[i][j],five[i][j]); // Here, dp[i][j] will store minimum number of 2's and 5's.
}
}
但上述并不是真正有效的答案,我不知道为什么?我实施了正确的方法吗?或者,这是解决这个问题的正确方法吗?
编辑:这是我计算一个数字中两个数和五个数的函数。
int calctwo (int foo)
{
int counter = 0;
while (foo%2 == 0)
{
if (foo%2 == 0)
{
counter++;
foo = foo/2;
}
else
break;
}
return counter;
}
int calcfive (int foo)
{
int counter = 0;
while (foo%5 == 0)
{
if (foo%5 == 0)
{
counter++;
foo = foo/5;
}
else
break;
}
return counter;
}
Edit2:链接中给出的I / O示例:
输入:
3
1 2 3
4 5 6
7 8 9
输出:
0
DDRR
答案 0 :(得分:3)
由于您只对尾随零的数量感兴趣,因此您只需要考虑2
,5
的功能,您可以将它们保存在两个单独的nxn
数组中。所以对于数组
1 2 3
4 5 6
7 8 9
你只需保留数组
the powers of 2 the powers of 5
0 1 0 0 0 0
2 0 1 0 1 0
0 3 0 0 0 0
问题的见解如下。请注意,如果找到最小化2的幂的总和的路径和最小化5的幂次数之和的路径,则答案是具有这两个路径的较低值的路径。因此,您将问题减少到以下经典dp问题的两次应用:找到一条路径,从左上角开始到右下角结束,这样它的元素总和最小。再次,按照这个例子,我们有:
minimal path for the
powers of 2 value
* * - 2
- * *
- - *
minimal path for the
powers of 5 value
* - - 0
* - -
* * *
所以你的回答是
* - -
* - -
* * *
值0
注1
看起来两条最优路径中的最小值只能给出一个上限,所以可能出现的问题是:这个界限是否实际达到了?答案是肯定的。为方便起见,让2的最佳路径中的2的数量为a
,沿5的最佳路径的5的数量为{{1} }。不失一般性假设两条最优路径的最小值是2的幂(即b
)的最小路径。让最小路径上的5的数量为a < b
。现在的问题是:是否存在多达5个,因为沿着这条路径有2个(即c
?)。假设答案是否定的。这意味着沿着最小路径(即c >= a
)的2比5更少。由于5路径的最佳值为c < a
,因此每5条路径至少有b
5个路径。对于最小路径,这也应该是正确的。这意味着b
。我们有c > b
所以c < a
,但最初的假设是a > b
。矛盾。
注2
您可能还需要考虑矩阵中存在元素a < b
的情况。当产品为1时,我假设尾随零的数量。在这种情况下,如果算法产生的值大于1,则应输出1并打印通过元素{{1 }}
答案 1 :(得分:0)
这是代码。我已使用action = "http://localhost:9767/ProspectWorxService.svc/SaveUploadedFile?Id=" + globalId
将因子2和5存储在矩阵中。
pair<int,int>
就我检查的测试用例而言,此代码可以得到很好的结果。如果您对此代码有任何疑问,请在评论中提问。
编辑:
基本的思维过程。
要到达目的地,只有2个选项。我从目的地开始,以避免路径提前计算的问题,因为如果2具有相同的最小值,那么我们选择其中任何一个。如果已计算到目的地的路径,则无关紧要。
最小的是检查哪一对更合适。如果一对具有最少2或5,则它将产生更少的0。
答案 2 :(得分:0)
这是一个使用Javascript和函数式编程的解决方案。 它依赖于几个功能:
smallest_trailer
递归遍历网格。我已选择进入4个可能的方向,左边&#34; L&#34;,右边&#34; R&#34;,向下&#34; D&#34;和&#34; U&#34;。在同一个细胞上传递两次是不可能的。选择的方向是尾随零数最小的方向。尾随零的计数用于另一个函数。zero_trailer(p,n,nbz)
假设您已到达具有值p
的单元格,而您已经拥有累加器n
并且在途中遇到nbz
个零。该函数返回一个包含两个元素的数组,即新的零数和新的累加器。累加器的功效为2或5.该函数使用辅助函数pow_2_5(n)
,它在n
内返回2和5的幂。deepCopy(arr)
生成数组arr
的标准深层副本,out_bound(i,j,n)
如果单元格(i,j)
超出网格范围则返回true大小为n
,myMinIndex(arr)
返回二维数组数组的最小索引(每个子数组包含尾随零的nb和作为字符串的路径)。 min只取决于子阵列的第一个元素。MAX_SAFE_INTEGER
是路径错误时最大尾随零数的(大)常量(例如,超出范围)。以下是代码,该代码适用于上述注释和原始链接中给出的示例。
var MAX_SAFE_INTEGER = 9007199254740991;
function pow_2_5(n) {
// returns the power of 2 and 5 inside n
function pow_not_2_5(k) {
if (k%2===0) {
return pow_not_2_5(k/2);
}
else if (k%5===0) {
return pow_not_2_5(k/5);
}
else {
return k;
}
}
return n/pow_not_2_5(n);
}
function zero_trailer(p,n,nbz) {
// takes an input two numbers p and n that should be multiplied and a given initial number of zeros (nbz = nb of zeros)
// n is the accumulator of previous multiplications (a power of 5 or 2)
// returns an array [kbz, k] where kbz is the total new number of zeros (nbz + the trailing zeros from the multiplication of p and n)
// and k is the new accumulator (typically a power of 5 or 2)
function zero_aux(k,kbz) {
if (k===0) {
return [1,0];
}
else if (k%10===0) {
return zero_aux(k/10,kbz+1);
}
else {
return [kbz,k];
}
}
return zero_aux(pow_2_5(p)*n,nbz);
}
function out_bound(i,j,n) {
return !((i>=0)&&(i<n)&&(j>=0)&&(j<n));
}
function deepCopy(arr){
var toR = new Array(arr.length);
for(var i=0;i<arr.length;i++){
var toRi = new Array(arr[i].length);
for(var j=0;j<arr[i].length;j++){
toRi[j] = arr[i][j];
}
toR[i] = toRi;
}
return toR;
}
function myMinIndex(arr) {
var min = arr[0][0];
var minIndex = 0;
for (var i = 1; i < arr.length; i++) {
if (arr[i][0] < min) {
minIndex = i;
min = arr[i][0];
}
}
return minIndex;
}
function smallest_trailer(grid) {
var n = grid.length;
function st_aux(i,j,grid_aux, acc_mult, nb_z, path) {
if ((i===n-1)&&(j===n-1)) {
var tmp_acc_nbz_f = zero_trailer(grid_aux[i][j],acc_mult,nb_z);
return [tmp_acc_nbz_f[0], path];
}
else if (out_bound(i,j,n)) {
return [MAX_SAFE_INTEGER,[]];
}
else if (grid_aux[i][j]<0) {
return [MAX_SAFE_INTEGER,[]];
}
else {
var tmp_acc_nbz = zero_trailer(grid_aux[i][j],acc_mult,nb_z) ;
grid_aux[i][j]=-1;
var res = [st_aux(i+1,j,deepCopy(grid_aux), tmp_acc_nbz[1], tmp_acc_nbz[0], path+"D"),
st_aux(i-1,j,deepCopy(grid_aux), tmp_acc_nbz[1], tmp_acc_nbz[0], path+"U"),
st_aux(i,j+1,deepCopy(grid_aux), tmp_acc_nbz[1], tmp_acc_nbz[0], path+"R"),
st_aux(i,j-1,deepCopy(grid_aux), tmp_acc_nbz[1], tmp_acc_nbz[0], path+"L")];
return res[myMinIndex(res)];
}
}
return st_aux(0,0,grid, 1, 0, "");
}
myGrid = [[1, 25, 100],[2, 1, 25],[100, 5, 1]];
console.log(smallest_trailer(myGrid)); //[0,"RDDR"]
myGrid = [[1, 2, 100],[25, 1, 5],[100, 25, 1]];
console.log(smallest_trailer(myGrid)); //[0,"DRDR"]
myGrid = [[1, 10, 1, 1, 1],[1, 1, 1, 10, 1],[10, 10, 10, 10, 1],[10, 10, 10, 10, 1],[10, 10, 10, 10, 1]];
console.log(smallest_trailer(myGrid)); //[0,"DRRURRDDDD"]
答案 3 :(得分:0)
这是我的动态编程解决方案。
https://app.codility.com/demo/results/trainingAXFQ5B-SZQ/
为了更好地理解,我们可以简化任务并假设矩阵中不存在零(即矩阵仅包含正整数),则Java解决方案如下:
class Solution {
public int solution(int[][] a) {
int minPws[][] = new int[a.length][a[0].length];
int minPws2 = getMinPws(a, minPws, 2);
int minPws5 = getMinPws(a, minPws, 5);
return min(minPws2, minPws5);
}
private int getMinPws(int[][] a, int[][] minPws, int p) {
minPws[0][0] = pws(a[0][0], p);
//Fullfill the first row
for (int j = 1; j < a[0].length; j++) {
minPws[0][j] = minPws[0][j-1] + pws(a[0][j], p);
}
//Fullfill the first column
for (int i = 1; i < a.length; i++) {
minPws[i][0] = minPws[i-1][0] + pws(a[i][0], p);
}
//Fullfill the rest of matrix
for (int i = 1; i < a.length; i++) {
for (int j = 1; j < a[0].length; j++) {
minPws[i][j] = min(minPws[i-1][j], minPws[i][j-1]) + pws(a[i][j], p);
}
}
return minPws[a.length-1][a[0].length-1];
}
private int pws(int n, int p) {
//Only when n > 0
int pws = 0;
while (n % p == 0) {
pws++;
n /= p;
}
return pws;
}
private int min(int a, int b) {
return (a < b) ? a : b;
}
}