【CQOI2013】二进制a+b 动态规划

题目描述

  输入三个整数a, b, c,把它们写成无前导0的二进制整数。比如a=7, b=6, c=9,写成二进制为a=111, b=110, c=1001。接下来以位数最多的为基准,其他整数在前面添加前导0,使得a, b, c拥有相同的位数。比如在刚才的例子中,添加完前导0后为a=0111, b=0110, c=1001。最后,把a, b, c的各位进行重排,得到a’, b’, c’,使得a’+b’=c’。比如在刚才的例子中,可以这样重排:a’=0111, b’=0011, c’=1010。
  你的任务是让c’最小。如果无解,输出-1。

数据范围

a,b,c<=2^30

样例输入

7 6 9

样例输出

10

解题思路

动态规划,f[i][j][k][l][m]表示在前i位,a,b,c还剩余j,k,l个1,m表示是否进位.
f[i+1][j-dj][k-dk][l-sum][m2]=min(f[i][j][k][l][Add]|(Sum*2^i))
dj<1,dk<2,sum=dj+dk+m,Add=sum>>1

代码

虽然猜到了是dp也还是完全不会写
↓↓↓这是标↓↓↓

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
bool g[33][33][33][33][2];
long long f[33][33][33][33][2];
int main(){
    int a=Getint(),b=Getint(),c=Getint(),Len[4],s[4];
    memset(Len,0,sizeof(Len));
    memset(s,0,sizeof(s));
    while(c){s[3]+=c%2;c/=2;Len[3]++;}while(a){s[1]+=a%2;a/=2;Len[1]++;}while(b){s[2]+=b%2;b/=2;Len[2]++;}
    memset(f,0x3f,sizeof(f));
    memset(g,0,sizeof(g));
    f[0][s[1]][s[2]][s[3]][0]=0;
    g[0][s[1]][s[2]][s[3]][0]=1;
    int L=max(Len[1],max(Len[2],Len[3]));
    for(int i=0;i<L;i++)
        for(int j=0;j<=s[1];j++)
            for(int k=0;k<=s[2];k++)
                for(int l=0;l<=s[3];l++)
                    for(int m=0;m<2;m++)
                        if(g[i][j][k][l][m])
                            for(int dj=0;dj<2;dj++)
                                for(int dk=0;dk<2;dk++){
                                    int Sum=dj+dk+m;
                                    int Add=Sum>>1;
                                    Sum&=1;
                                    int tmp=f[i][j][k][l][m]|(Sum<<i);
                                    if(j>=dj&&k>=dk&&l>=Sum){
                                        g[i+1][j-dj][k-dk][l-Sum][Add]=1;
                                        if(f[i+1][j-dj][k-dk][l-Sum][Add]>tmp)
                                            f[i+1][j-dj][k-dk][l-Sum][Add]=tmp;
                                    }
                                }
    cout<<(g[L][0][0][0][0]?f[L][0][0][0][0]:-1);
    return 0;
}

转载于:https://www.cnblogs.com/Cedric341561/p/6811037.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值