给定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
给定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
, b
受a<=m
和b<=n
的限制。
你可以通过
-
计算x和y的最大公约数,
d = GCD(x,y)
。 -
如果
z
不是d
的倍数,则无解 -
如果
z
能被d
整除,则计算z' = z / d
、x' = x / d
、y' = y / d
-
使用扩展欧几里得算法求解
a'
和b'
的修正方程z' = a'x' + b'y'
(基本上是一个循环,运行时间为O(log(max(z, x, y))) -
通过
a'
和b'
乘以z'
计算a
和b
-
检查解是否满足
a<=m
和b<=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;
}
你的问题是减少到找到a
和b
这样的z=ax+by
,而a<=m
和b<=n
。您可以只使用一个循环迭代a
并为b
求解方程z=ax+by
来解决它,同时检查条件b<=n
。就是这样。
- 通过组合不同的类型来创建唯一的id
- 如何通过组合多个字符数组来创建字符数组?
- Visual Studio 2017 是否有用于创建单行注释的特定键盘组合?
- 找不到如何创建使用指针、字符和 for 函数组合的程序
- 创建多个向量的所有可能组合
- GTKMM GLADE?(创建组合框文本 Entery框)
- 在数组C++中创建所有可能的非唯一整数组合
- Qt C++根据组合框中的选择创建一个对象
- 使用参数组合创建对象
- 从而在2D侧滚动游戏中创建障碍物的组合
- C++动态创建的MFC视觉工作室填充组合框
- 使用deque和递归C++创建所有可能的组合
- 在重载函数的函数参数中使用右值引用会创建太多组合
- 如何创建具有不同项目字符串的两个不同的组合框
- IM 创建一个 C++ 程序,其中用户可以尝试 2 次尝试密码用户名组合.如果他们无法获得它,他们的程序就会停止
- 使用所有可用字体(从C#到C++/CLI)创建组合框
- 如何创建全局处理 Win+<some 键>组合的应用?
- 如何创建Qt组合框
- std::ios::openmode的组合,如果文件存在,则截断,但防止创建新文件
- 给定m块x英寸的砖块和n块y英寸的砖块,使用给定砖块的组合创建z英寸的行