CSU2034 Column Addition

2034: Column Addition

2034: Column Addition
题目大意:给出一个加法竖式,和一个错误答案,去掉若干列让竖式成立,例如:
       12127      117
      + 45618   = > + 468
      ———–    ———
       51825       585
那么输出需要去掉的列数的最小数量。
这道题比赛的时候很早就有思路了,用DP思想,设DP[i]为当前列不删除的情况下,需要删除的最少列数。因为状态由低位向高位转移,所以删除的一定是低位列。每一个不删除的列的状态来自于前一列或者是最近的没有删除的列,这些列的进位使得当前列计算正确,那么状态就得到保持,如果当前列一定要删除,那么DP[i] = -1;
   状态转移方程: dp[i]=min(dp[i],dp[j]+ji1),{j=i+1,..,n|a[i]+b[i]+jw[j]%10} d p [ i ] = m i n ( d p [ i ] , d p [ j ] + j − i − 1 ) , { j = i + 1 , . . , n | a [ i ] + b [ i ] + j w [ j ] % 10 }
这里的a,b数组是对应的加数,jw数组是第i位的和的进位情况取值为1或者0。
  需要注意的是最高位情况需要单独判断,因为它不可以有进位的情况。有则一定要删除最高位。
比赛还是因为心急没有过去,仅仅因为公式写错了一点。下不为例。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<string>
#include<stdlib.h>
using namespace std;
const int maxn  = 1000+5;
char cha[maxn],chc[maxn],chb[maxn];
int a[maxn],b[maxn],c[maxn];
int dp[maxn],jw[maxn];

int main()
{
    //freopen("h.in","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;
    while(scanf("%d",&n)==1 && n )
    {
        for(int i=0;i<n;i++) dp[i]==-1;
        scanf("%s",cha);
        scanf("%s",chb);
        scanf("%s",chc);
        for(int i=0; i<n; i++)
        {
            a[i] = cha[i]-'0';
            b[i] = chb[i]-'0';
            c[i] = chc[i]-'0';
        }
        dp[n-1] = ((a[n-1]+b[n-1])%10==c[n-1]?0:-1);
        if((a[n-1]+b[n-1])%10==c[n-1])
            jw[n-1] = (a[n-1]+b[n-1]>9?1:0);
        for(int i=n-2; i>0; i--)
        {
            dp[i] = ((a[i]+b[i])%10==c[i]?n-i-1:-1);
            if((a[i]+b[i])%10==c[i])
                jw[i] = (a[i]+b[i]>9?1:0);

            for(int j=i+1; j<n; j++)
            {
                if((a[i]+b[i]+jw[j])%10 == c[i]&&dp[j]!=-1)
                {
                    if(dp[i]!=-1)
                        dp[i] = min(dp[i],dp[j]+j-i-1);
                    else
                        dp[i] = dp[j]+j-i-1;
                    jw[i] = (a[i]+b[i]+jw[j]>9?1:0);
                }
            }
        }
        dp[0] = ((a[0]+b[0])==c[0]?n-1:-1);
        for(int j=1;j<n;j++) {
            if((a[0]+b[0])+jw[j] == c[0] &&dp[j]!=-1){
                    if(dp[0]!=-1)
                        dp[0] = min(dp[0],dp[j]+j-1);
                    else
                        dp[0] = dp[j]+j-1;
            }
        }
        int minn = n;
        for(int i=0;i<n;i++) {
            if(dp[i]+i<minn &&dp[i]!=-1 && !jw[i])
                minn = dp[i]+i;
        }
        printf("%d\n",minn);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值