codeforces-2B The least round way(dp+路径记录)

链接:http://codeforces.com/problemset/problem/2/B
题意:在一个棋盘上从左上角走到右下角,求经过点的乘积的结果尾数的0最少,要输出路径

题解:记录每个格子2和5的因子数,做两次dp,取较小的那个。有0的情况要特殊判断,可以把0当作10,最后的结果如果大于1,那么按照经过0来处理。记录路径记录前驱即可。但是不知道test 31为何wa了。。

代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<stack>
using namespace std;

int n, a[1002][1002];
int num[1002][1002][2]; //0表示2因子个数,1表示5因子个数
int dp[1002][1002][2];
int path[1002][1002][2];
int mov[1002*1002];

int zx = -1, zy = -1;

void output(int k){
    /*if(i == 1 && j == 1){
        return;
    }
    if(path[i][j][k] == 1){
        output(i-1, j, k);
        printf("D");
    }
    else{
        output(i, j-1, k);
        printf("R");
    }*/
    int cnt = 0;
    int i = n, j = n;
    while(i!=1 || j!=1){
        if(path[i][j][k] == 1){
            mov[cnt++] = 1;
            i = i-1;
        }
        else{
            mov[cnt++] = 0;
            j = j-1;
        }

    }
    for(int i = cnt-1; i>=0; i--){
        if(mov[i] == 1) printf("D");
        else printf("R");
    }
    printf("\n");
}


int main(){
    scanf("%d", &n);
    for(int i = 1; i<=n; i++){
        for(int j = 1; j<=n; j++){
            scanf("%d", &a[i][j]);
        }
    }
    for(int i = 1; i<=n; i++){
        for(int j = 1; j<=n; j++){
            int temp = a[i][j];
            if(a[i][j] == 0){
                temp = 10;
                zx = i; zy = j;
            }
            while(temp%2 == 0){
                num[i][j][0]++;
                temp/=2;
            }
            while(temp%5 == 0){
                num[i][j][1]++;
                temp/=5;
            }
        }
    }

    /*for(int i = 1; i<=n; i++){
        for(int j = 1; j<=n; j++){
            cout<<num[i][j][0]<<"-"<<num[i][j][1]<<" ";
        }
        cout<<endl;
    }*/

    for(int i = 1; i<=n; i++){
        dp[1][i][0] = dp[1][i-1][0]+num[1][i][0];
        path[1][i][0] = 0;
        dp[i][1][0] = dp[i-1][1][0]+num[i][1][0];
        path[i][1][0] = 1;
        dp[1][i][1] = dp[1][i-1][1]+num[1][i][1];
        path[1][i][1] = 0;
        dp[i][1][1] = dp[i-1][1][1]+num[i][1][1];
        path[i][1][1] = 1;
    }

    for(int i = 2; i<=n; i++){
        for(int j = 2; j<=n; j++){
            dp[i][j][0] = min(dp[i-1][j][0], dp[i][j-1][0])+num[i][j][0];
            path[i][j][0] = dp[i-1][j][0]>dp[i][j-1][0]?0:1;
            dp[i][j][1] = min(dp[i-1][j][1], dp[i][j-1][1])+num[i][j][1];
            path[i][j][1] = dp[i-1][j][1]>dp[i][j-1][1]?0:1;
        }
    }
    int res;
    res = min(dp[n][n][0], dp[n][n][1]);
    int k = dp[n][n][0]>dp[n][n][1]?1:0;
    /*for(int i = 1; i<=n; i++){
        for(int j = 1; j<=n; j++){
            cout<<path[i][j][1]<<" ";
        }
        cout<<endl;
    }
    cout<<endl;

    for(int i = 1; i<=n; i++){
        for(int j = 1; j<=n; j++){
            cout<<dp[i][j][1]<<" ";
        }
        cout<<endl;
    }*/
    if(zx!=-1){
        printf("1\n");
        for(int i = 1; i<zx; i++){
            printf("D");
        }
        for(int i = 1; i<=n; i++){
            printf("R");
        }
        for(int i = zx; i<n; i++){
            printf("D");
        }
        printf("\n");
    }
    else{
        printf("%d\n", res);
        output(k);
    }
    //cout<<dp[2][3][0]<<" "<<dp[3][3][1]<<endl;


    return 0;
}

猜你喜欢

转载自blog.csdn.net/grimcake/article/details/79873944