时间限制:
10000ms
单点时限:
1000ms
内存限制:
256MB
描述
给定一个N行N列的非负整数方阵,从左上角(1,1)出发,只能向下或向右走,且不能到达值为0的方格,求出一条到达右下角的最佳路径。所谓最佳路径是指途经的数的乘积的末尾连续的0最少。
输入
输入文件的第一行包含一个整数N,其中1≤N≤1000。
接下来的N行每行包含N个非负整数,其中每个数小于等于1,000,000。
数据保证至少存在一条不全为0的路径。最佳路径是指途经的数的乘积的末尾连续的0最少
输出
输出文件仅一行,包含一个整数,表示要求的最佳路径上所有数字乘积的末尾连续零的个数。
样例输入4 1 3 0 0 0 8 2 25 6 5 0 3 0 15 7 4
2解题思路 该题的要求是找出一条最佳途数的乘积的末尾连续的0最少的一条路径。则重点在于如何判断0最少。 可知: 10=2*5 那么换一个角度来说,只要结果的末尾有0,那么经过的路径的元素必有2的倍数以及5的倍数(题目中已经要求不经过值为0的点)。从而,问题则可以转化为,求取一条路径,使得该路径经过的各个点的值中,存在因子2的个数或存在因子5的个数最小。 根据以上分析,我们可以将问题分为两个部分进行: (1)求取存在因子2个数最少的一条路径 (2)求取存在因子5个数最少的一条路径 对于上述两个部分,其原理是相同的,都可以看做是动态规划的问题进行求解: 对于方阵中任意一点(i,j): 其最短路径dp[i][j]=min(dp[i][j],min(dp[i-1][j],dp[i][j-1])+w[i][j])
根据上述的关系式,则可以完成代码的编写。
AC代码如下:
#include<iostream>
#include<math.h>
#include<cstring>
#include<algorithm>
using namespace std;
int mod5(int data);
int mod2(int data);
int p[1010][1010]={0};
int dp[1010][1010]={0};
int w[1010][1010]={0};
int main(){
int N;
cin>>N;
for(int i=1;i<=N;i++){
for(int j=1;j<=N;j++){
cin>>p[i][j];
if (p[i][j]==0)
w[i][j]=1e5;
}
}
memset(dp,0x3f,sizeof dp);
dp[1][0]=0;
for(int i=1;i<=N;i++){
for(int j=1;j<=N;j++){
if(p[i][j]!=0){
w[i][j]=mod2(p[i][j]);
}
dp[i][j]=min(dp[i][j],min(dp[i][j-1],dp[i-1][j])+w[i][j]);
}
}
int ans=dp[N][N];
memset(dp,0x3f,sizeof dp);
dp[1][0]=0;
for(int i=1;i<=N;i++){
for(int j=1;j<=N;j++){
if(p[i][j]!=0){
w[i][j]=mod5(p[i][j]);
}
dp[i][j]=min(dp[i][j],min(dp[i][j-1],dp[i-1][j])+w[i][j]);
}
}
cout<<min(dp[N][N],ans)<<endl;
return 0;
}
int mod2(int data){
int k=data;
int mod2=0;
while(k%2==0){
mod2++;
k=k/2;
}
return mod2;
}
int mod5(int data){
int k=data;
int mod5=0;
while(k%5==0){
mod5++;
k=k/5;
}
return mod5;
}