给定m块x英寸的砖块和n块y英寸的砖块,使用给定砖块的组合创建z英寸的行

Given m bricks of x inches and n bricks of y inches, create row of z inches using combination of the given bricks

本文关键字:组合 创建 给定      更新时间:2023-10-16

给定m个小砖(每个x英寸长)和n个大砖(每个y英寸长),我们想要使用小砖和大砖的组合创建一个z英寸长的行。编写一个程序来验证是否有可能创建这样一行砖块。

的例子,

输入:我们有4(m)个3英寸(x)长的小砖块和3(n)个4英寸(y)长的大砖块。我们需要创建14(z)英寸长的行。

输出:是的

输入:我们有2(m)个2英寸(x)长的小砖块和2(n)个5英寸(y)长的大砖块。我们需要创建的行长度为6(z)英寸。

输出:No(没有砖块组合成6英寸长的墙)。

这是我在面试过程中被问到的问题。我用c++写了下面的代码

#include <iostream>
using namespace std;
int main()
{ int m,x,n,y,z;
  int small=0, large=0, sum=0;
  cout<<"Enter values : ";
  cin>>m>>x>>n>>y>>z;
  int i=0,j=0,flag=0;
  for(i=0;i<m;i++)
    {   small=small+x;
        for(j=0;j<=n;j++)
            {   large=large+y;
                sum=small+large;
                if(sum==z || sum==small || sum==large)
                {
                cout<<"nYes. Combination Possible";
                flag=1;
                }
                else if(sum>z && large>z)
                break;  
            }
        large=0;
    }
if(flag==0)
cout<<"nNo. Not possible";
return 0;
}

如何使用单循环或甚至不使用循环来解决这个问题?

注:不允许解Mx+Ny=Z。任何其他的替代解。

你基本上尝试了所有的组合,当你找到一个有效的组合时,你甚至没有停下来,你只是继续尝试所有的组合。这当然可以改进:我要么1)当你设置flag = 1;时使用break;,然后在外部循环中使用if (flag == 1) break;,这样你就可以从两个循环中断开,或者2)使用goto跳转到循环的末尾(但这在面试中非常危险,因为你可能会发现有人讨厌goto…),或者3)直接使用cout << "Yes" << endl; exit(0);

不管怎样,我想他们想让你实现一些分支定界算法。例如,在你的方法中,你尝试从小的开始,然后你尝试添加长的。假设通过采取i小的,你已经超越了z:它是否有意义,也尝试采取0,1,2,…n长砖?你已经知道你做得太过分了。如果你从i=0, j=0开始并不断增加,并且对于给定的i,你已经超过了z,那么你肯定没有解决方案,你可以只使用cout << "No" << endl; exit(0);。或者,假设对于当前的i,您没有超出z,那么您进入内部循环并开始添加长块。如果在某一点上你超越了z,那么尝试添加更多砖块是否有意义?显然不是,您最好从内循环中取出break,然后再用一个小砖块尝试一次。换句话说:当你确定自己走得太远时,停下来。这意味着对于当前的分支,你的下界高于你必须达到的值,也就是说,这个分支必须被丢弃,因为它不能给你一个解决方案。然后,要么直接退出(如果像第一种情况一样,您确定没有其他分支可以为您带来解决方案),要么转到下一个分支。

你也可以做相反的事情:如果,对于i的当前值,你看到即使通过所有n长的砖块你也没有达到z,这意味着尝试内部循环是浪费时间,你可以,从外部循环,continue;到下一次迭代,其中i增加。但这需要一点数学计算(可以在if (i*x + n*y < z)中完成),考虑到您所给出的约束,这可能是不允许的。无论如何,这对应于检查你的上界是不是太低。如果是,则跳过此分支并继续。

我不认为有一个单循环的解决方案。如果你被迫使用一定数量的砖块,比如10个,你可以从10个小砖块开始检查,如果你没有达到z,你可以用一个长砖块交换一个小砖块,这样尝试:0和10,1和9,2和8,以此类推,直到10和0。这是一个单循环。但是没有办法提前知道你需要多少块砖。我能想到的所有捷径都需要解决一些像Mx+Ny=Z这样的方程,这是不被接受的。

所以我会选择分支和定界:与其尝试所有的组合,不如试着理解你是否在浪费时间,在这种情况下,继续前进。

方法:

用大砖块填充整行,不超过所需的长度z
现在检查剩余长度是否为小砖块长度的倍数。
如果是,而且我们有足够的小砖块,我们就有答案了。如果没有,移除一块大砖块(只要还有大砖块),然后再尝试添加小砖块。如果小砖块的数量不足以达到所需的长度,则完成。

代码:

#include <iostream>
using namespace std;
int main () {
   int m;   // number of small bricks
   int x;   // length of small bricks
   int n;   // number of big bricks
   int y;   // length of big bricks
   int z;   // length of wall
   cout << "Enter values : ";
   cin >> m >> x >> n >> y >> z;
   int flag = 0;
   for (int numBig = min(z / y, n); numBig >= 0; numBig--) {
      int sum = numBig * y;
      if ((z - sum) % x == 0) {
         int numSmall = (z - (numBig * y)) / x;
         if (numSmall <= m) {
            cout << "Yes. Combination Possible" << endl;
            flag = 1;
            break;
         } else {
            break;   // not enough small bricks
         }
      }
   }
   if (flag == 0)
      cout << "No. Not possible" << endl;
   return 0;
}

你的任务实际上是解一个线性丢番图方程,形式为

z = ax + by

另外,我们正在寻找的未知a, ba<=mb<=n的限制。

你可以通过

  1. 计算x和y的最大公约数,d = GCD(x,y)

  2. 如果z不是d的倍数,则无解

  3. 如果z能被d整除,则计算z' = z / dx' = x / dy' = y / d

  4. 使用扩展欧几里得算法求解a'b'的修正方程z' = a'x' + b'y'(基本上是一个循环,运行时间为O(log(max(z, x, y)))

  5. 通过a'b'乘以z'计算ab

  6. 检查解是否满足a<=mb<=n约束

    #include <iostream>
using namespace std;
int main()
{
   int m;   // number of small bricks
   int x;   // length of small bricks
   int n;   // number of big bricks
   int y;   // length of big bricks
   int z,z1,flag=0,flag1=0,m1,n1;   // length of wall
    cin>>m;
    cin>>x;
    cin>>n;
    cin>>y;
    cin>>z;
    z1=z;
    m1=m;n1=n;
    while(z>=0&&m>=0){
        if(z%x==0){
            if(m>=z/x){
                flag=1;
                break;
            }
        }
        if(z%y==0){
            if(n>=z/y){
                flag=1;
                break;
            }
        }
        z=z-x;
        m--;
    }
    while(z1>=0&&n1>=0){
        if(z1%x==0){
            if(m1>=z1/x){
                flag1=1;
                break;
            }
        }
        if(z1%y==0){
            if(n1>=z1/y){
                flag1=1;
                break;
            }
        }
        z1=z1-y;
        n1--;
    }
    if(flag1==1 || flag==1){
        cout<<"Possble";
    }
    else{
        cout<<"Not Possible";
    }
    return 0;
}

你的问题是减少到找到ab这样的z=ax+by,而a<=mb<=n。您可以只使用一个循环迭代a并为b求解方程z=ax+by来解决它,同时检查条件b<=n。就是这样。