CodeForces B. The least round way(dp)

转自:https://blog.csdn.net/u012860063/article/details/40517115

题目链接:http://codeforces.com/problemset/problem/2/B

B. The least round way
time limit per test 5 seconds
memory limit per test 64 megabytes
input standard input
output standard output
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.

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).

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

Sample test(s)
input
3
1 2 3
4 5 6
7 8 9
output
0
DDRR

题意:

从左上到右下! 选出一条能让走过的路径的数字的积中含有最少的零!

PS:

积要含有零只能是2 或者5形成!寻找一条含有2或者5 最少的路径即可!

注意判断矩阵中是否有零的情况!

代码如下:
 

//http://blog.csdn.net/azheng51714/article/details/8240390
#include <cstdio>
#include <cstring>
const int maxn = 1017;
int m[2][maxn][maxn];
int dp[2][maxn][maxn];
//dp[0][i][j]到i、j时有多少个2;
//dp[1][i][j]到i、j时有多少个5;
int vis[2][maxn][maxn];
int n;
 
int solve(int mark)
{
    vis[mark][1][1] = 0;
    dp[mark][1][1] = m[mark][1][1];
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            if(i==1 && j==1)
                continue;
            if(i == 1)
            {
                dp[mark][i][j] = dp[mark][i][j-1] + m[mark][i][j];
                vis[mark][i][j] = 1;//向右
            }
            else if(j == 1)
            {
                dp[mark][i][j] = dp[mark][i-1][j] + m[mark][i][j];
                vis[mark][i][j] = 0;//向下
            }
            else
            {
                int tt1 = dp[mark][i-1][j];
                int tt2 = dp[mark][i][j-1];
                if(tt1 < tt2)
                {
                    dp[mark][i][j] = tt1 + m[mark][i][j];
                    vis[mark][i][j] = 0;
                }
                else
                {
                    dp[mark][i][j] = tt2 + m[mark][i][j];
                    vis[mark][i][j] = 1;
                }
            }
        }
    }
    return dp[mark][n][n];
}
 
void print(int mark, int x, int y)
{
    if(x==1 && y==1)
        return ;
    if(vis[mark][x][y] == 0)
    {
        print(mark,x-1,y);
        printf("D");
    }
    else
    {
        print(mark,x,y-1);
        printf("R");
    }
}
 
int main()
{
    int x, y;
    while(~scanf("%d",&n))
    {
        int tt, t1, t2;
        memset(vis,0,sizeof(vis));
        memset(m,0,sizeof(m));
        int flag = 0;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                scanf("%d",&tt);
                if(tt == 0)
                {
                    flag = 1;
                    x = i;
                    y = j;
                    continue;
                }
                t1 = t2 = tt;
                while(t1%2 == 0)
                {
                    t1/=2;
                    m[0][i][j]++;
                }
                while(t2%5 == 0)
                {
                    t2/=5;
                    m[1][i][j]++;
                }
            }
        }
 
        int ans1 = solve(0);//路径存在最少的2的个数
        int ans2 = solve(1);//路径存在最少的5的个数
        //printf("ans1:%d ans2:%d\n",ans1,ans2);
        int mark = 0;
        int ans = 0;
        if(ans1 < ans2)
        {
            ans = ans1;
            mark = 0;
        }
        else
        {
            ans = ans2;
            mark = 1;
        }
        if(flag && ans > 1)
        {
            printf("1\n");//有零存在那么最终结果就只有一个零
            for(int i = 2; i <= x; i++)
            {
                //向下到有零的那一行
                printf("D");
            }
            for(int j = 2; j <= n; j++)
            {
                //走到最右边
                printf("R");
            }
            for(int i = x+1; i <= n; i++)
            {
                //走到最下边
                printf("D");
            }
            printf("\n");
            continue;
        }
        printf("%d\n",ans);
        print(mark, n, n);
        printf("\n");
    }
    return 0;
}
 
/*
3
4 10 5
10 9 4
6 5 3
3
4 10 5
6 0 2
7 8 9
*/

//添加说明(即为啥是ans=min(2的最小,5的最小)

1.当在2的个数最小的路径上,不会出现比单单在5的个数最小的路径下更小的了

2.同理当在5的个数最小的路径上,不会出现比单单在2的个数最小的路径下更小的了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值