【问题标题】:Given length and number of digits,we have to find minimum and maximum number that can be made?给定长度和位数,我们必须找到可以制作的最小和最大数字?
【发布时间】:2015-07-22 04:58:12
【问题描述】:

正如问题所述,我们得到一个正整数 M 和一个非负整数 S。我们必须找到长度为 M 和数字总和为 S 的数字中的最小和最大。

约束:

(S>=0 和 S

(M>=1 和 M

我想了想,得出的结论一定是动态编程。但是我没有建立DP状态

这是我的想法:-

dp[i][j]=总和为“j”的前“i”位数字

并尝试制作程序。这是它的样子

/*
  *** PATIENCE ABOVE PERFECTION ***
    "When in doubt, use brute force. :D"

    -Founder of alloj.wordpress.com

*/

#include<bits/stdc++.h>

using namespace std;

#define pb push_back

#define mp make_pair

#define nline cout<<"\n"

#define fast ios_base::sync_with_stdio(false),cin.tie(0)

#define ull unsigned long long int

#define ll long long int

#define pii pair<int,int>

#define MAXX 100009

#define fr(a,b,i) for(int i=a;i<b;i++)

vector<int>G[MAXX];


int main()
{
    int m,s;

    cin>>m>>s;

    int dp[m+1][s+1];

    fr(1,m+1,i)

     fr(1,s+1,j)

       fr(0,10,k)
          dp[i][j]=min(dp[i-1][j-k]+k,dp[i][j]); //Tried for Minimum

    cout<<dp[m][s]<<endl;

    return 0; 
}

请指导我这个 DP 状态以及程序的时间复杂度。这是我第一次尝试 DP。

【问题讨论】:

  • 这里不需要dp,是贪心算法
  • Exactly Greedy 是一种更好的方法,只需找到具有此属性的数字,然后对数字进行递增或递减排序。

标签: dynamic-programming


【解决方案1】:
dp solution goes here :-

#include<iostream>


using namespace std;

int dp[102][902][2] ;
void print_ans(int m , int s , int flag){
    if(m==0)
        return ;
    cout<<dp[m][s][flag];
    if(dp[m][s][flag]!=-1)
        print_ans(m-1 , s-dp[m][s][flag] , flag );
    return ;
}
int main(){
    //freopen("problem.in","r",stdin);
    //freopen("out.txt","w",stdout);
    //int t;
    //cin>>t;
    //while(t--){
    int m , s ;
    cin>>m>>s;
    if(s==0){
        cout<<(m==1?"0 0":"-1 -1");
        return 0;
    }
    for(int i = 0 ; i <=m ; i++){
        for(int j=0 ; j<=s ;j++){
            dp[i][j][0]=-1;
            dp[i][j][1]=-1;
        }
    }
    for(int i = 0 ; i < 10 ; i++){
        dp[1][i][0]=i;
        dp[1][i][1]=i;
    }
    for(int i = 2 ; i<=m ; i++){
        for(int j = 0 ; j<=s ; j++){
            int flag = -1;
            int f = -1;
            for(int k = 0 ; k <= 9 ; k++){
                if(i==m&&k==0)
                    continue;
                if( j>=k && flag==-1 && dp[i-1][j-k][0]!=-1)
                    flag = k;
            }
            for(int k = 9 ; k >=0 ;k--){
                if(i==m&&k==0)
                    continue;
                if( j>=k && f==-1 && dp[i-1][j-k][1]!=-1)
                    f = k;
            }
            dp[i][j][0]=flag;
            dp[i][j][1]=f;
        }
    }
    if(m!=0){
        print_ans(m , s , 0);
        cout<<" ";
        print_ans(m,s,1);
    }
    else
        cout<<"-1 -1";
        cout<<endl;
//  }
}

【讨论】:

  • 这里使用print_ans函数打印ans。
【解决方案2】:

DP 状态为 (i,j)。它可以被认为是根据递归定义的数学函数的参数(较小的问题,因此是子问题!)

更深入, 状态通常是唯一识别问题的参数数量,以便我们始终知道我们在计算什么!

让我们仅以您的问题为例

为了定义您的问题,我们将需要该州的数字数 + 可以用这些数字形成的总和(注意:您在遍历数字时会集体保持总和!)

我认为对于 state 部分来说已经足够了。

现在,

动态规划的运行时间非常简单。

首先让我们看看一个问题中有多少个子问题:

您需要填写每个状态,即您必须涵盖小于或等于整个问题的所有独特子问题! 循环关系知道哪个问题小于另一个问题!

例如: 斐波那契数列

F(n)=F(n-1)+F(n-2)

注意基本情况,永远是最小的子问题。!! 注意这里对于 F(n) 我们必须计算 F(n-1) 和 F(n-2) ,它将达到 n=1 的阶段,您需要返回基本情况! 因此子问题的总数可以说是基本情况和当前问题之间的所有问题!

现在, 在自下而上,我们需要根据这个基本案例和问题之间的大小来处理每个状态!

现在,这告诉我们运行时间应该是

O(子问题数 * 每个子问题的时间)。

那么在您的解决方案 DP[0][0] 到 DP[M][S] 中存在多少子问题 对于每个问题,您都运行 10 个循环

O(M*S (子问题) * 10)

砍掉那个常数! 但它不一定总是一个常数!

这里有一些你可能想看的代码!随便问什么!

#include<bits/stdc++.h>
using namespace std;
bool DP[9][101];
int Number[9][101];
int main()
{
    DP[0][0]=true;  // It is possible to form 0 using NULL digits!!
    int N=9,S=100,i,j,k;
    for(i=1;i<=9;++i)
        for(j=0;j<=100;++j)
        {
            if(DP[i-1][j])
            {
                for(k=0;k<=9;++k)
                    if(j+k<=100)
                        {
                            DP[i][j+k]=true;
                            Number[i][j+k]=Number[i-1][j]*10+k;
                        }
            }
        }
    cout<<Number[9][81]<<"\n";
    return 0;
}

您可以使用回溯而不是直接存储数字,因为您的约束条件很高!

DP[i][j]表示是否可以仅使用i个数字形成数字总和!

Number[i][j]

是我懒惰避免输入回溯方式(困了,已经凌晨 3 点了)

我正在尝试添加所有可能的数字来扩展状态。

本质上是一种前卫的DP风格!!您可以在Topcoder了解更多信息

【讨论】:

  • 注意,如果你投反对票,请告诉我原因加上 OP 最后要求这个而不是问题!!
  • 感谢您的努力 :) 能否请您演示一下这个问题中的状态如何。再次感谢
  • dp[i][j]=直接在您的语言中总和为 'j' 的前 'i' 位数字
  • 实际上,您的思维过程是正确的,但我担心您的转换是错误的 + 您已经正确定义了状态,但您忘记提及它告诉我们的内容!正确的定义是是否可以使用 i 位来计算 j 的总和!我宁愿为此添加一些代码
猜你喜欢
  • 1970-01-01
  • 2018-12-11
  • 1970-01-01
  • 2012-10-22
  • 2019-02-14
  • 1970-01-01
  • 2018-08-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多