C++ 动态规划:计算中间的数字
给定两个数字C++ 动态规划:计算中间的数字,c++,string,algorithm,optimization,dynamic-programming,C++,String,Algorithm,Optimization,Dynamic Programming,给定两个数字X和Y,它们之间有多少个数字至少有一半的数字相同?例如,1122和4444将起作用,而11234和112233将不起作用 显然,最简单的方法是从X开始,一直递增1到Y,然后检查每个数字,但这太慢了,因为X和Y的边界介于100和10^18之间。我知道这是动态规划的一种形式,我应该用字符串来表示数字,但我不能再进一步了 任何帮助都可以接受。谢谢 显然,考虑范围内的所有数字并不能做到这一点。相反,从生成所需数字的角度考虑。例如,设计一个函数,该函数将生成所有符合条件的数字,给定的长度不超过
X
和Y
,它们之间有多少个数字至少有一半的数字相同?例如,1122
和4444
将起作用,而11234
和112233
将不起作用
显然,最简单的方法是从X
开始,一直递增1到Y
,然后检查每个数字,但这太慢了,因为X
和Y
的边界介于100
和10^18
之间。我知道这是动态规划的一种形式,我应该用字符串来表示数字,但我不能再进一步了
任何帮助都可以接受。谢谢 显然,考虑范围内的所有数字并不能做到这一点。相反,从生成所需数字的角度考虑。例如,设计一个函数,该函数将生成所有符合条件的数字,给定的长度不超过以数字为单位的长度 例如,对于5位数字,您希望所有数字至少有三个1或三个2,或者。。。你能一次完成吗,或者你需要把三个1和更多的分开吗 现在你已经考虑过了,想想这个:与其生成所有这些数字,不如数一数。例如,对于三个1和两个其他数字,您有9*9对其他数字(请确保不要重复计算11122之类的数字)。你可以用10种方式排列1,另外两个数字可以互换 请注意,偶数数字的问题有点不同:必须避免对半和对半数字重复计数,例如111222 这能让你动起来吗
对12月3日评论的回应 @bobjoe628:这不是一个完整的算法;相反,这是一个让你开始的建议。是的,你有几个组合问题要处理。至于11122233,我不确定我是否理解您的担忧:与任何此类排列问题一样,您必须处理每个数字与其兄弟姐妹之间的可互换性。有10C5种分配1的方式;在剩余的点中,有5C3种方式分配2;其他两个插槽为3'3。现成的算法(即浏览器搜索)将涵盖这些阴谋 我相信您可以编写一个生成数字的算法:请注意,您只需要一个数字组合,因此按升序生成数字是安全的,正如您所给出的示例:111112233。一旦您生成了这些数字,您的组合代码应该覆盖这些数字的所有唯一排列
最后,请注意,大多数语言都有支持包,可以为您执行排列和组合。我将在以下几个步骤中向您解释: 第一步: 为了解决
X
和Y
之间的这类范围问题,总是通过在0到X
和0到Y-1
之间进行计数,然后减去结果来简化。i、 e.如果您有一个类似于f(N)
的函数,该函数计算的数字中至少有一半的位数在0和N之间相同,那么您的最终结果是:
f(X) - f(Y-1)
第二步:
接下来我们要计算f(N)。我们将此函数分为两个子函数,一个子函数用于计算与N位数相同的数字的结果(我们称之为f_等于),另一个子函数用于计算小于N位数的合格数字(我们称之为f_小于)。例如,如果N是19354,我们计算0到9999之间的限定数字,然后在另一种方法中计算10000到19354之间的最喜欢的数字,然后我们总结结果。接下来,我将解释如何实现这两种方法
第三步:
这里,我们要计算无f_的方法。你可以通过一些数学来做,但我总是喜欢写一个简单的DP来解决这些任务。我将编写递归函数,不管您是使用memonization还是使用一些循环自下而上(我将留给您作为练习)
long-long f_-less(int curDigit,int favNum,int favNumCountSoFar,int nonavnum,int nonavnumcountsofar,int maxDigit){
if(curDigit==maxDigit){
//对于具有偶数maxDigit的数字,可能有两个最喜欢的数字
//我们应该只数一次,比如522552
if(favNumCountSoFar*2==maxDigit&&favNumCountSoFar==nonavnumcountsofar)返回1;
如果(2*favNumCountSoFar>=maxDigit)返回2;
返回0;
}
长res=0;
对于(inti=(curDigit==0?1:0);这里是一个部分组合答案。我省略了如何使用函数构造完整答案
(请参见此处,以获取具有更详细注释的相同代码:)
固定最左边的数字,L
,在R
数字位于L
右侧的数字中,我们可以通过以下方式计算分配(N/2)
或更多数字d
的方式:
Python代码
导入数学、运算符、集合
#假设L至少有一个数字集
#f({'string':'12','digital_frequencies':[0,1,0,0,0,0,0],'num_digital_frequencies':2},6)
def f(左,右):
R=N-len(L['string'])
计数=0
计数=假
对于L[‘数字频率’]中的数字频率:
开始=整数(数学单元(N/2.0))-数字频率
如果开始>R:
持续
对于X范围内的i(开始,R+1):
如果不是(N&1)且未计算在内:
如果L['num_digital_frequencies']=1而不是digital_frequency,且i==N/2:
计数=计数-选择(R,i)
如果L['num_digit_frequencies']=2和digit_frequency而不是任何([x>N/2表示L['digit_frequencies']]中的x)和i+digit_frequency==N/2:
计数=计数-选择(R,i)
计数=Tr
long long f_less(int curDigit, int favNum, int favNumCountSoFar, int nonFavNum, int nonFavNumCountSoFar, int maxDigit){
if(curDigit == maxDigit ){
//for numbers with even maxDigit there may be a case when we have 2 favorite numbers
//and we should count them only once. like 522552
if(favNumCountSoFar*2 == maxDigit && favNumCountSoFar == nonFavNumCountSoFar) return 1;
if(2*favNumCountSoFar >= maxDigit) return 2;
return 0;
}
long long res = 0;
for(int i=(curDigit==0?1:0);i<=9;++i) //skip the leading zero
if(i==favNum)
res += f_less(curDigit+1, favNum, favNumCountSoFar + 1, nonFavNum, nonFavNumCountSoFar,maxDigit);
else
res += f_less(curDigit+1, favNum, favNumCountSoFar, i, (i==nonFavNum?nonFavNumCountSoFar+1:1),maxDigit);
return res;
}
long long res = 0;
for(int maxDigit = 1; maxDigit < NUMBER_OF_DIGITS(N); ++maxDigit)
for(int favNumber = 0; favNumber < 10; ++favNumber)
res += f_less(0, favNumber, 0, -1, 0, maxDigit);
string s = NUM_TO_STRING(N);
int maxDigit = s.size();
long long f_equal(int curDigit, int favNum, int favNumCountSoFar,int nonFavNum, int nonFavNumCountSoFar, bool isEqual){ //isEqual checks that whether our number is equal to N or it's lesser than it
if(curDigit == maxDigit ){
//for numbers with even maxDigit there may be a case when we have 2 favorite numbers
//and we should count them only once. like 522552
if(favNumCountSoFar*2 == maxDigit && favNumCountSoFar == nonFavNumCountSoFar) return 1;
if(2*favNumCountSoFar >= maxDigit) return 2;
return 0;
}
long long res = 0;
for(int i=(curDigit==0?1:0);i<=9;++i){ //skip the leading zero
if(isEqual && i>(s[curDigit]-'0')) break;
if(i==favNum)
res += f_equal(curDigit+1, favNum, favNumCountSoFar + 1, nonFavNum, nonFavNumCountSoFar, isEqual && (i==(s[curDigit]-'0')));
else
res += f_equal(curDigit+1, favNum, favNumCountSoFar, i, (i==nonFavNum?nonFavNumCountSoFar+1:1), isEqual && (i==(s[curDigit]-'0')));
}
return res;
}
long long res = 0;
for(int favNumber = 0; favNumber < 10; ++favNumber)
res += f_equal(0, favNumber,0, -1, 0, true);
float getCount(int x, int y) {
if(x == y) return 0.0; // Special case (no numbers are between x and y)
return INFINITY; // The closest value to the correct answer that a computer can use
}