您的位置:首页 > 其它

codeforces 2B.The least round way(数学&dp)

2018-01-16 17:21 537 查看

The least round way

Description

There is a square matrix n × n, consisting of non-negative integer numbers. You should find such a way on it that

starts in the upper left cell of the matrix;

each following cell is to the right or down from the current cell;

the way ends in the bottom right cell.

Moreover, if we multiply together all the numbers along the way, the result should be the least “round”. In other words, it should end in the least possible number of zeros.

给定一个n*n的矩阵,找到一条从左上角到右下角的路线(只能往右/下走),使路过的数字乘积有最少后缀0

Input

The first line contains an integer number n (2 ≤ n ≤ 1000), n is the size of the matrix. Then follow n lines containing the matrix elements (non-negative integer numbers not exceeding 109).

第一行输入n,然后输入矩阵

Output

In the first line print the least number of trailing zeros. In the second line print the correspondent way itself.

第一行一个数字表示做少后缀0的数量,第二行输入路线(右和下分别用’R’和’D’表示)

Hint

我们通过数学知识知道,后缀0代表该数是10的倍数,应由若干2*5产生,我们把每个格子里的数因数分解预处理出它包含的2和5的数量,则用a[i][j][0]表示因子中2的数量,用a[i][j][1]表示因子中5的数量

则问题转化为:从左上角到右下角找一条路径,使得路过的min(2,5)最小

则dp方程很好设计:dp[i][j][0/1]=min(dp[i−1][j][0/1],dp[i][j−1][0/1])+a[i][j][0/1]

其中dp[i][j][0]表示从左上角到(i,j)经过的最少2数,dp[i][j][1]表示从左上角到(i,j)经过的最少5数,还要用c数组记录路径(或者递归找路径)

! 注意:如果出现0,经过它的路径就会只有1个后缀0,但是可能找到没有后缀0的路径,所以我们先把0当成10

Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define MAX 1007

using namespace std;

int n,x;
int dp[2][MAX][MAX];
int p[2][MAX][MAX];

void print ( int x , int y , int k , int f  ) {
if ( x == 1 && y == 1 );
else if ( x == 1 ) print ( x , y-1 , k , 0);
else if ( y == 1 ) print ( x-1 , y , k , 1);
else {
if ( dp[k][x][y] == dp[k][x-1][y] + p[k][x][y] )
print ( x-1 , y , k , 1 );
else print ( x , y-1 , k , 0);
}
if ( f == 3 ) return;
printf ( "%c" , f?'D':'R' );
}

int main ( ) {
while ( ~scanf ( "%d" , &n ) ) {
int flag = 0,a,b;
for ( int i = 1 ; i <= n ; i++ )
for ( int j = 1 ; j <= n ; j++ ) {
scanf ( "%d" , &x );
if ( !x ) {
flag = 1;
p[0][i][j]++;
p[1][i][j]++;
a = i , b = j;
continue;
}
while ( x%2 == 0 ) {
p[0][i][j]++;
x /= 2;
}
while ( x%5 == 0 ) {
p[1][i][j]++;
x /= 5;
}
}
memset ( dp , 0x3f , sizeof ( dp ) );
for ( int k = 0 ; k < 2 ; k++ )
for ( int i = 1 ; i <= n ; i++ )
for ( int j = 1 ; j <= n ; j++ ) {
if ( i-1 )
dp[k][i][j] = min ( dp[k][i][j] , dp[k][i-1][j] );
if ( j-1 )
dp[k][i][j] = min ( dp[k][i][j] , dp[k][i][j-1] );
if ( i == j && i == 1 )
dp[k][i][j] = 0;
dp[k][i][j] +=  p[k][i][j];
}
int ans = min ( dp[0]

, dp[1]

);
if ( ans > 1 && flag ) {
puts ( "1"<
aec7
/span> );
for ( int i = 1 ; i < a ; i++ )
printf ( "%c" , 'D' );
for ( int j = 1 ; j < b ; j++ )
printf ( "%c" , 'R' );
for ( int i = a ; i < n ; i++ )
printf ( "%c" , 'D' );
for ( int j = b ; j < n ; j++ )
printf ( "%c" , 'R' );
puts ( "" );
continue;
}
printf ( "%d\n" , ans );
if ( dp[0]

< dp[1]

)
print ( n , n , 0 , 3 );
else print ( n , n , 1 , 3 );
puts ( "" );
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数学 dp