B - The least round way(DP、路径还原)

B - The least round way

link
题意:给定n×n方正,从右上角出发走到左下角,要求所有经过路径得到的数乘积中0的个数最少。
输出最小数、还原路径

碎碎念:一开始写的转移方程判断条件是判断2、5与当前的个数相加后取最小值,判断哪个小走哪个。假的。正解应该一直对2和5一直取最小的,在最后再取最小值。手推一下就okk

零的个数就是所有乘数中2的个数和5的个数的最小值
注意如果路径中存在0,要做特殊标记。含有0可以使答案恒为1
递归思想还原路径,注意输出在递归后,这样才是从头开始走

wa了好多test29,记得把边界的最大值设置为maxn×maxn不是maxn

int n;
struct node{
    int tw,fi;
}dp[maxn][maxn],mp[maxn][maxn];
void way1(int x,int y){
    if(x==1&&y==1)
        return;
    if(x==1){
        for(int i=1;i<y;i++)
            cout<<"R";
        return;
    }
    if(y==1){
        for(int i=1;i<x;i++)
            cout<<"D";
        return;
    }
    if(dp[x][y].tw-mp[x][y].tw==dp[x-1][y].tw){
        way1(x-1,y);
        cout<<"D";
    }
    else{
        way1(x,y-1);
        cout<<"R";

    }
}
void way2(int x,int y){
    if(x==1&&y==1)
        return;
    if(x==1){
        for(int i=1;i<y;i++)
            cout<<"R";
        return;
    }
    if(y==1){
        for(int i=1;i<x;i++)
            cout<<"D";
        return;
    }
    if(dp[x][y].fi-mp[x][y].fi==dp[x-1][y].fi){
        way2(x-1,y);
        cout<<"D";
    }
    else{
        way2(x,y-1);
        cout<<"R";
    }
}
int main(){
    n=ird();
    for(int i=0;i<=n+1;i++){//边界条件设置
        dp[i][0].tw=maxn*maxn;
        dp[0][i].tw=maxn*maxn;
        dp[i][0].fi=maxn*maxn;
        dp[0][i].fi=maxn*maxn;
    }
    int f=0,xx,yy;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int t=ird();
            if(t==0){
                f=1;
                xx=i;
                yy=j;
                continue;
            }
            while(t%2==0){
                mp[i][j].tw++;
                t/=2;
            }
            while(t%5==0){
                mp[i][j].fi++;
                t/=5;
            }
            if(i==1&&j==1){
                dp[i][j].tw+=mp[i][j].tw;
                dp[i][j].fi+=mp[i][j].fi;
                continue;
            }
            dp[i][j].fi=min(dp[i][j-1].fi,dp[i-1][j].fi)+mp[i][j].fi;
            dp[i][j].tw=min(dp[i][j-1].tw,dp[i-1][j].tw)+mp[i][j].tw;
        }
    }
    if(min(dp[n][n].tw,dp[n][n].fi)==0||f==0){
        cout<<min(dp[n][n].tw,dp[n][n].fi)<<endl;
        if(dp[n][n].tw<dp[n][n].fi){
            way1(n,n);//2的个数是限制条件
        }
        else way2(n,n);//5的个数是限制条件
        cout<<endl;
    }
    else{//路径中有0的情况,并且没有一条路径可以不含0的情况
        cout<<1<<endl;
        for(int i=1;i<xx;i++) cout<<"D";
        for(int i=1;i<yy;i++) cout<<"R";
        for(int i=xx;i<n;i++) cout<<"D";
        for(int i=yy;i<n;i++) cout<<"R";
        cout<<endl;
    }
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值