读书人

一个有点棘手的数字分解算法

发布时间: 2012-02-16 21:30:36 作者: rapoo

求助,一个有点棘手的数字分解算法
问题如下:
已知一个数A,求出A=x1+x2+x3+x4的所有组合,其中,x1,x2,x3,x4的最小值为1,他们的最大值分别为给定的一个数字。
例如:A=60,x1,x2,x3,x4的最大值分别为x1=13,x2=26,x3=24,x4=19,则求出这几个数相加得60的所有组合。
若有好的算法,不胜感谢!

[解决办法]
提示:

1 * 2 3 * 4 ... * ...57 58 59 60 ... A

* 为分隔符,要把 A 分为 n 个数的和就有 n-1 个*
然后求 A 的 n-1 的组合(即 * 的位置),再用位置相减得出每个数字。
比如求出组合1, 3, 56 则
x1 = 1 - 0 = 1
x2 = 3 - 1 = 2
x3 = 56 - 3 = 53
x4 = 60 - 56 = 4
再去除重复得结果即可

stl 可以产生组合

[解决办法]
求所有组合,是没有好解法的,这明显是一个遍历问题,对A,x1,x2,x3,x4较大的情况,符合条件的组合是很多的,运算时间短不了。

如果是求组合个数,那才有意思。
[解决办法]
既然是“所有组合”,最必须是穷举。可用三套for循环,但其中略有讲究。
为了避免重复,我们先约定 x1 <= x2 <= x3 <= x4
由此可见
x1 <= (int)(A / 4)
x2 <= (int)(A / 3) && x2 > = x1
……

for(int x1 = 1; x1 <= A/4; x1++)
for(int x2 = x1; x2 <= A/3; x2++)
for(int x3 = x2; x3 <= A/2; x3++) {
int x4 = A - x1 - x2 - x3;
if(x4 < x3) break;
else 输出:x1, x2, x3, x4
}



[解决办法]
#include "iostream "
#include "fstream "
using namespace std;

int main()
{
int x1,x2,x3,x4,num=0;
const sum=60;
const int mx1=13,mx2=26,mx3=24,mx4=19;

ofstream fout( "result.txt ",ios::out);

for(x1=1;x1 <mx1;x1++)
for(x2=1;x2 <mx2;x2++)
for(x3=1;x3 <mx3;x3++)
{
x4=sum-x1-x2-x3;
if(x4> =1&&x4 <=mx4)
{
fout < < "x1= " < <x1 < < " x2= " < <x2 < < " x3= " < <x3 < < " x4= " < <x4 < <endl;
num++;
}
}

fout < < "Total number of solutions: " < <num < <endl;

fout.close();

return 0;
}
[解决办法]
若x1,x2,x3,x4的最大值加在一起也小于A,则无解
然后是遍历,遍历时的方法如下,对于Xi,遍历范围是A-(Max(X(i+1))+...+Max(X4))到Max(Xi)
也就是对于X1,范围是1~13,对于X2,由于60-24-19-X1到26,以此类推。
public class Summary
{
public static void main(String[] args)
{
int maxX1 = 13;
int maxX2 = 26;
int maxX3 = 24;
int maxX4 = 19;
int sum = 60;
int l;
for (int i = max(sum - maxX2 - maxX3 - maxX4, 1); i <= maxX1; i++)
{
for (int j = max(sum - i - maxX3 - maxX4, 1); j <= maxX3; j++)
{
for (int k = max(sum - i - j - maxX4, 1); k <= maxX3; k++)
{
l = sum - i - j - k;
if (l > 0)
{
System.out.println(i + " " + j + " " + k + " " + l);
}
}
}
}
}

private static int max (int i, int j)
{
if (i > j)
{
return i;
}
return j;
}
}

[解决办法]
我的想法是,先看成 A=x1+A1, A2=x2+x3+x4;

A1=x2+A2,A2=x3+A4
……
以此类推,代码如下

public class Main {
private static final int idim[]={13,26,24,19}; //题目给定的各个数的最大值
private static final int n=60; //所求的和
private static int isum[]=new int [idim.length-1]; //为打印各组合准备的数组


private static int is=0; //记录总共有多少种结果
private static final int or=1; //0,不打印各组合,只打印结果总数;1,打印各组合
public static void main(String args[]) {
int a=0;
for (int i = 0; i < idim.length; i++) {
a+=idim[i];
}
if (a <n) {
System.out.print( "无解。 ");
System.exit(0);
}
f(1,n); //进行 A = x1+ A1。
//1 是标记x;n 表示 x+剩下的数的和
System.out.print(is);
}
public static void f( int x,int y ) {
if ( x==idim.length ) {
if (or==1) {
int a=0;
for (int i = 0; i < x-1; i++) {
a+=isum[i];
System.out.print(isum[i]+ "\t ");
}
System.out.print((n-a)+ "\n ");
}
is++;
} else {
int a=0;
for (int i = x; i < idim.length; i++) {
a+=idim[i];
}
int b=( (1+a)> y ) ? 1:(y-a);
int c=( idim[x-1]+1> y ) ? (y-1):idim[x-1];
for (int i = b; i < c+1; i++) {
isum[x-1]=i;
f(x+1,y-i);
}
}
}
}
[解决办法]
1、计算A=60,x1,x2,x3,x4的所有组合M。
2、计算A=60,当x1> 13的所有组合。依次当x2> 26 ,x3> 24 ,x4> 19,的所有组合M1。
3、计算A=60,当x1> 13和x2> 26的所有组合,还有其他的两两结合的组合 计算得M2
4、计算A=60,当x1> 13和x2> 26和x3> 24的所有组合,以及其他三三结合的组合 计算得M3
5、计算A=60当x1> 13和x2> 26和x3> 24和x4> 19的所有组合M4

最后M1-M2+M3-M4
[解决办法]
计算A=60,当x1> 13的所有组合时
相当于计算(13+x1`)+x2+x3+x4=60

读书人网 >软件架构设计

热点推荐