题目大意:给定规定大小的方阵。要求从方阵的左上方出发到达右下方。每次只能向右边或者向下方移动。求得所有路过数的连续乘法的积, 使得结果的末尾有最少的0。
题目分析:
1. 使得最终结尾的0最少,等价于结果中2和5成对的数量最少。对因子2和因子5进行两次dp, 求两次结果的最小值即可;
2.如果存在矩阵元素0, 如果最终结果0的数量大于等于1,那么结果就不会比存在0的路径最优。预处理时可以把0当做10;
3.假设二维dp, 形如dp(i, j), 表示在i, j位置结果拥有最少的因子2或因子5.
使得最终结果有最少的2和最少的5, 递推公式为:
dp[ i ][ j ] = min( dp[ i - 1][ j ], dp[ i ][ j - 1] ) + two(five)[ i ][ j ];
解题代码:
/*************************************************************************
> File Name: main.cpp
> Author: gxg
> Method: dp + 路径还原
> Created Time: 2017年02月13日 星期一 15时20分31秒
************************************************************************/
#include <bits/stdc++.h>
using namespace std;
const int Max = 1111;
int n, tmp; // n 是矩阵大小, tmp记录输入的矩阵元素
int two[Max][Max], five[Max][Max], path[Max][Max][2]; //two[][]记录矩阵元素预处理的因子2的个数
//five[][]记录矩阵元素预处理的因子5的个数
//记录两次dp的路径
int x, y; //记录零元素的坐标
int main()
{
scanf("%d", &n);
int zero = 0; //标记矩阵元素是否存在零
for (int i = 1; i <= n; ++ i)
{
for (int j = 1; j <= n; ++ j)
{
scanf("%d", &tmp);
if(tmp == 0)
{
zero++;
tmp = 10; //将0当做10处理
x = i, y = j;
}
//预处理
int cnt = 0;
while(tmp % 2 == 0) tmp /= 2, cnt++; two[i][j] = cnt;
cnt = 0;
while(tmp % 5 == 0) tmp /= 5, cnt++; five[i][j] = cnt;
}
}
//边界处理
for (int i = 1; i <= n; ++ i) two[i][1] += two[i-1][1], five[i][1] += five[i-1][1];
for (int i = 1; i <= n; ++ i) five[1][i] += five[1][i-1], two[1][i] += two[1][i-1];
for (int i = 1; i <= n; ++ i) path[i][1][0] = path[i][1][1] = 0, path[1][i][0] = path[1][i][1] = 1; //0表示向下, 1表示向右
//dp过程
for (int i = 2; i <= n; ++ i)
{
for (int j = 2; j <= n; ++ j)
{
//two[i][j] += min(two[i-1][j], two[i][j-1]);
if(two[i-1][j] < two[i][j-1]) two[i][j] += two[i-1][j], path[i][j][0] = 0;
else two[i][j] += two[i][j-1], path[i][j][0] = 1;
//five[i][j] += min(five[i-1][j], five[i][j-1]);
if(five[i-1][j] < five[i][j-1]) five[i][j] += five[i-1][j], path[i][j][1] = 0;
else five[i][j] += five[i][j-1], path[i][j][1] = 1;
}
}
int result = min(two[n][n], five[n][n]);
//选择最终路径
int cho = 0;
if(two[n][n] >= five[n][n]) cho = 1;
//零元素存在且必须输出零元素所在路径的情况
if(zero && result >= 1)
{
printf("1\n");
int x1 = n - x, y1 = n - y;
x--, y--;
while(x--) putchar('R');
while(y--) putchar('D');
while(x1--) putchar('D');
while(y1--) putchar('R');
return 0;
}
printf("%d\n", result);
x = n, y = n;
vector<char> vec;
while(x != 1 || y != 1)
{
if(path[x][y][cho] == 0) vec.push_back('D'), x--;
else vec.push_back('R'), y--;
}
for (int i = vec.size() - 1; i >= 0; -- i) putchar(vec[i]);
printf("\n");
return 0;
}