Codeforces 2B. The least round way(动态规划)

给一个矩阵,找到从左上到右下角的路径

使得路径上的数字乘积0最少, 每次只能从当前位置到右侧或下侧相邻位置

首先要想到乘积为0对应因子为2、5

我刚开始的思路是每次找到与当前位置数所得结果0最少的,也就是2、 5一起考虑

但这样写不仅太复杂,而且是不对的

正解应该是分别考虑2最少的和5最少的情况

这道题卡了好几天。。。

另外有个坑就是矩阵中可能含0,这时结果肯定为经过0的路径,且答案为1

代码能力太挫。。。写了近200行尴尬

代码如下:

/* ***********************************************
Author        : yinwoods
E-Mail        : yinwoods@163.com
Created Time  : 2014年12月15日 星期一 19时48分02秒
File Name     : 2B.cpp
************************************************ */

#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXN 1010
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

int a[MAXN][MAXN];
struct DP {
    int val, from;//记录前一个状态位置,1表示从左侧来,2表示从上方来
}dp2[MAXN][MAXN], dp5[MAXN][MAXN];

int main(void) {
    int n;
    int x0, y0;
    bool ok0 = false;
    scanf("%d", &n);
    for(int i=1; i<=n; ++i) {
        for(int j=1; j<=n; ++j) {

            scanf("%d", &a[i][j]);
            int tmp = a[i][j];
            if(tmp == 0) {//如果含0,记录位置
                x0 = i;
                y0 = j;
                ok0 = true;
                continue;
            }

            if(tmp%2 == 0) {
                while(tmp%2 == 0) {
                    tmp /= 2;
                    ++dp2[i][j].val;//对应找到2最少的路径的DP
                }
            }
            if(tmp%5 == 0) {
                while(tmp%5 == 0) {
                    tmp /= 5;
                    ++dp5[i][j].val;//对应找到5最少的路径的DP
                }
            }
        }
    }

    for(int i=2; i<=n; ++i) {
        dp2[1][i].val += dp2[1][i-1].val;
        dp2[1][i].from = 1;
        dp2[i][1].val += dp2[i-1][1].val;
        dp2[i][1].from = 2;

        dp5[1][i].val += dp5[1][i-1].val;
        dp5[1][i].from = 1;
        dp5[i][1].val += dp5[i-1][1].val;
        dp5[i][1].from = 2;
    }

    for(int i=2; i<=n; ++i) {
        for(int j=2; j<=n; ++j) {
            int tmp1 = dp2[i-1][j].val;
            int tmp2 = dp2[i][j-1].val;
            if(tmp1 < tmp2) {
                dp2[i][j].val += tmp1;
                dp2[i][j].from = 2;
            } else {
                dp2[i][j].val += tmp2;
                dp2[i][j].from = 1;
            }
            tmp1 = dp5[i-1][j].val;
            tmp2 = dp5[i][j-1].val;
            if(tmp1 < tmp2) {
                dp5[i][j].val += tmp1;
                dp5[i][j].from = 2;
            } else {
                dp5[i][j].val += tmp2;
                dp5[i][j].from = 1;
            }
        }
    }
    /*
    for(int i=1; i<=n; ++i) {
        for(int j=1; j<=n; ++j)
            printf("%d ", dp2[i][j].val);
        puts("");
    }
    */

    int x, y;
    string ans;
    x = y = n;
    while(x!=1 || y!=1) {
        int tmp = dp2[x][y].from;
        if(tmp == 1) {
            ans.push_back('R');
            --y;
        } else {
            ans.push_back('D');
            --x;
        }
    }
    string ans2 (ans.rbegin(), ans.rend());//找到2最少的路径
    //printf("2 -- %d\t", dp2[n][n].val);
    //cout << ans2 << endl;

    ans.clear();
    x = y = n;
    while(x!=1 || y!=1) {
        int tmp = dp5[x][y].from;
        if(tmp == 1) {
            ans.push_back('R');
            --y;
        } else {
            ans.push_back('D');
            --x;
        }
    }
    string ans5(ans.rbegin(), ans.rend());//找到5最少的路径
    //printf("5 -- %d\t", dp5[n][n].val);
    //cout << ans5 << endl;

    struct RES {
        int two, five;
        RES() {
            two = five = 0;
        }
    }res2, res5;
    x = y = 1;
    for(int i=0; ; ++i) {//从路径推出结果含0个数
        int tmp = a[x][y];
        //printf("%d\n", tmp);
        while(tmp && tmp%2 == 0) {
            ++res2.two;
            tmp /= 2;
        }
        tmp = a[x][y];
        while(tmp && tmp%5 == 0) {
            ++res2.five;
            tmp /= 5;
        }
        if(i >= ans2.size())
            break;
        if(ans2[i] == 'D') {
            ++x;
        } else ++y;
    }

    x = y = 1;
    for(int i=0; ; ++i) {//从路径推出结果含0个数
        int tmp = a[x][y];
        //printf("%d\n", tmp);
        while(tmp && tmp%2 == 0) {
            ++res5.two;
            tmp /= 2;
        }
        tmp = a[x][y];
        while(tmp && tmp%5 == 0) {
            ++res5.five;
            tmp /= 5;
        }
        if(i >= ans5.size())
            break;
        if(ans5[i] == 'D') {
            ++x;
        } else ++y;
    }
    //printf("%d - %d\n", res2.two, res2.five);
    //printf("%d - %d\n", res5.two, res5.five);
    int tmp1 = min(res2.two, res2.five);
    int tmp2 = min(res5.two, res5.five);
    if(ok0 && min(tmp1, tmp2)>1) {//如果矩阵中含0
        puts("1");
        for(int i=1; i<x0; ++i) {
            printf("D");
        }
        for(int i=1; i<y0; ++i) {
            printf("R");
        }
        for(int i=x0; i<n; ++i) {
            printf("D");
        }
        for(int i=y0; i<n; ++i)
            printf("R");
    }
    else if(tmp1 < tmp2) {
        cout << tmp1 << endl << ans2 << endl;
    } else {
        cout << tmp2 << endl << ans5 << endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值