题目描述
输入三个整数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;
}