几天没休息好,头昏脑胀,求个算法

该用户不懒但没有名字 2013-10-24 05:18:04
几天没休息好,头昏脑胀,求个算法

已知:
一个大数V,很大
数字A
数字B
数字C
数字D
数字...
A、B、C、D、...这些数字远小于V,而且他们的和(A+B+C+D+...)也远小于V
求满足如下条件:
A1*x1+B1*x2+C1*x3+D1*x4+...=V

A1<=A
B1<=B
C1<=C
D1<=D
并且x1>x2>x3>x4


的所有
A1-x1
B1-x2
C1-x3
D1-x4
的组合
--------------------------------------------
例如
V=654321
A=54
B=257
C=19
D=360

求满足如下条件
A1*x1+B1*x2+C1*x3+D1*x4=V
A1<=A
B1<=B
C1<=C
D1<=D
并且x1>x2>x3>x4
的所有
A1-x1
B1-x2
C1-x3
D1-x4
的组合
...全文
519 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
attidust 2013-10-25
  • 打赏
  • 举报
回复
楼主这个算法是要用来破译密码吗?这么多不确定性。
feiniao19830822 2013-10-25
  • 打赏
  • 举报
回复
V越大,ABC个数越多,ABC数值越小,组合就越多。 只考虑A1=A,B1=B,C1=C,D1=D,即54*x1+257*x2+19*x3+360*x4=654321,限定条件 x1>x2>x3>x4,且x4>0的情况下, 用递归算了一下,组合有40375394种。用时64秒左右(把打印部分注释掉了),这个应该没有什么算法,只能递归吧?

        private static int iGroupCnt = 0;
        private static int[] arrSum;
        private static int[] arrFloorSum;

        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            int[] arrABC = new int[] { 54, 257, 19, 360 };
            int V = 654321;

            //存放x1x2x3x4
            int[] arrX = new int[arrABC.Length];

            //为了处理x1>x2>x3>x4的限定条件,加的2个数组
            arrSum = new int[arrABC.Length];
            arrFloorSum = new int[arrABC.Length];
            for (int i = 0; i < arrABC.Length; i++)
            {
                if (i > 0)
                {
                    arrSum[i] = arrSum[i - 1] + arrABC[i];
                    arrFloorSum[i] = arrFloorSum[i - 1] + arrSum[i - 1];
                }
                else
                {
                    arrSum[i] = arrABC[i];
                }
            }

            //当前处理的数的序号,右边的x值最小,从右边的数开始
            //序号
            int iCurIndex = arrABC.Length - 1;
            //值
            int iCur = arrABC[iCurIndex];
            //组合次数
            iGroupCnt = 0;
            //遍历函数
            IterateFun(arrABC, iCurIndex, arrX, V);

            ////如果考虑A1<=A,B1<=B,C1<=C,D1<=D的情况
            ////再外面加循环就行了,我给个嵌套的写法,你可以改成递归的方式,以适应ABC个数不确定
            //int[] arrABC2 = new int[arrABC.Length];
            //for (int i = 0; i < arrABC[0] + 1; i++)
            //{
            //    arrABC2[0] = i;
            //    for (int j = 0; j < arrABC[1] + 1; j++)
            //    {
            //        arrABC2[1] = j;
            //        for (int m = 0; m < arrABC[2] + 1; m++)
            //        {
            //            arrABC2[2] = m;
            //            for (int n = 0; n < arrABC[3] + 1; n++)
            //            {
            //                arrABC2[3] = n;
            //                IterateFun(arrABC2, iCurIndex, arrX, V);
            //            }
            //        }
            //    }
            //}

            sw.Stop();
            Console.WriteLine("组合数:" + iGroupCnt);
            Console.WriteLine("花费:"+sw.ElapsedMilliseconds+"毫秒");

            Console.ReadLine();
        }

        /// <summary>
        /// 递归函数
        /// </summary>
        /// <param name="arrABC">ABC数组</param>
        /// <param name="iCurIndex">当前序号</param>
        /// <param name="arrX">x1x2数组</param>
        /// <param name="VRemain">V剩余值</param>
        private static void IterateFun(int[] arrABC, int iCurIndex, int[] arrX, int VRemain)
        {
            //当前序号对应的值
            int iCur = arrABC[iCurIndex];
            if (iCurIndex < 1)
            {
                //如果还剩下A没有计算,直接判断能否整除
                int iRemainder = VRemain % iCur;
                if (iRemainder == 0 )
                {
                    int iQuotient = VRemain / iCur;
                    arrX[iCurIndex] = iQuotient;
                    //输出到屏幕中
                    //string s = "";
                    //for (int i = 0; i < arrIn.Length; i++)
                    //{
                    //    s += string.Format("{0}*{1}+", arrIn[i], arrLoop[i]);
                    //}
                    //s = s.TrimEnd('+');
                    //Console.WriteLine(s);
                    iGroupCnt++;
                    
                }
            }
            else
            {    
                //如果x1x2不考虑为0的情况,请将此处改为1
                int iMinX = 0;

                //前N项ABC之和
                int iSum = arrSum[iCurIndex];
                //因为x1>x2>x3>x4的限定,所以当计算x4时要减去(3x1+2x2+x3)
                int iFloorSum = arrFloorSum[iCurIndex];
                int iVRemainTmp = VRemain - iFloorSum;

                //考虑x1>x2>x3>x4限定后,X的最大取值,包括此最大值
                int iMaxX = iVRemainTmp / iSum;

                //当前X最小值不能比后面的X小
                if (iCur < arrX.Length - 1)
                {
                    iMinX = arrX[iCurIndex + 1] + 1;
                }

                for (int i = iMinX; i < iMaxX + 1; i++)
                {
                    arrX[iCurIndex] = i;
                    //遍历
                    IterateFun(arrABC, iCurIndex - 1, arrX, VRemain - i * iCur);
                }
            }
        }
wy619118470 2013-10-25
  • 打赏
  • 举报
回复
条件给的太少 V既然可以无限大 越大的变化 ABCD越多
  • 打赏
  • 举报
回复
引用 13 楼 u011303459 的回复:
如果再考虑A1<=A,B1<=B,C1<=C,D1<=D, 为了便于计算。 A1取值范围是 1-54 B1取值范围是 1-257 C1取值范围是 1-19 D1取值范围是 1-360 这样排列组合有54*257*19*360种,每种组合都有1千万种排列,这样看计算机都要算很久的。
空间复杂度可以适当放宽点。
  • 打赏
  • 举报
回复
引用 12 楼 reenjie 的回复:
[quote=引用 8 楼 ohsorry 的回复:] [quote=引用 6 楼 reenjie 的回复:] 單單這些條件還不夠吧,數字的正負或者數字為整型還是浮點型都沒有明確說明。
不好意思,所有数字都是正整数,可以是0。 A、B 、C、 D……这些数字至少有3个[/quote] 條件還是不全。這樣導致結果很多,而且值不確定。 假設一結果是這樣:D為1,A、B、C都為0符合條件。那么x4=V,但是X1,X2,X3值就不確定。 樓主給出的條件不全,這樣即使有人想幫忙,也做不出來啊。[/quote] 那就暂时别考虑0了,解决核心复杂问题就行了
feiniao19830822 2013-10-25
  • 打赏
  • 举报
回复
如果再考虑A1<=A,B1<=B,C1<=C,D1<=D, 为了便于计算。 A1取值范围是 1-54 B1取值范围是 1-257 C1取值范围是 1-19 D1取值范围是 1-360 这样排列组合有54*257*19*360种,每种组合都有1千万种排列,这样看计算机都要算很久的。
reenjie 2013-10-25
  • 打赏
  • 举报
回复
引用 8 楼 ohsorry 的回复:
[quote=引用 6 楼 reenjie 的回复:] 單單這些條件還不夠吧,數字的正負或者數字為整型還是浮點型都沒有明確說明。
不好意思,所有数字都是正整数,可以是0。 A、B 、C、 D……这些数字至少有3个[/quote] 條件還是不全。這樣導致結果很多,而且值不確定。 假設一結果是這樣:D為1,A、B、C都為0符合條件。那么x4=V,但是X1,X2,X3值就不確定。 樓主給出的條件不全,這樣即使有人想幫忙,也做不出來啊。
feiniao19830822 2013-10-25
  • 打赏
  • 举报
回复
可能性太多了,即使只考虑A1=A,B1=B,C1=C,D1=D这一种情况,在x1>x2>x3>x4,且x4>0的情况下,程序已算到7万中组合了, 目前54*9983+257*333+19*1542+360*1 可以看出x4还停留在1,这样看来,组合起码1千万种
_小黑_ 2013-10-25
  • 打赏
  • 举报
回复
坐 等 大 牛
DashBird 2013-10-25
  • 打赏
  • 举报
回复
即便求Ax1+Bx2+Cx3+……+Zx4=V,就不好求吧
小飞牛coder 2013-10-25
  • 打赏
  • 举报
回复
不知所云
feiniao19830822 2013-10-25
  • 打赏
  • 举报
回复
引用 22 楼 ohsorry 的回复:
[quote=引用 21 楼 u011303459 的回复:]
引用
只考虑A1=A,B1=B,C1=C,D1=D就大打折扣了吗。
注释白写了,你太懒了。
看到了,不过我也看到了嵌套4曾的for循环。。。,什么数量级。[/quote] 有多少种组合是客观的,算法改变的只是速度。按你目前的需求,组合本来就多,我在13就说明了,这个和采用什么算法无关。还有一点你要明白,当A1B1C1D1很小的时候,组合更多,比如A1=B1=C1=D1=1,V = 654321的时候,你自己算算有多少种组合吧。
  • 打赏
  • 举报
回复
引用 21 楼 u011303459 的回复:
引用
只考虑A1=A,B1=B,C1=C,D1=D就大打折扣了吗。
注释白写了,你太懒了。
看到了,不过我也看到了嵌套4曾的for循环。。。,什么数量级。
feiniao19830822 2013-10-25
  • 打赏
  • 举报
回复
引用
只考虑A1=A,B1=B,C1=C,D1=D就大打折扣了吗。
注释白写了,你太懒了。
公西雒 2013-10-25
  • 打赏
  • 举报
回复
看到这些条件我就凌乱了
  • 打赏
  • 举报
回复
引用 17 楼 u011303459 的回复:
V越大,ABC个数越多,ABC数值越小,组合就越多。 只考虑A1=A,B1=B,C1=C,D1=D,即54*x1+257*x2+19*x3+360*x4=654321,限定条件 x1>x2>x3>x4,且x4>0的情况下, 用递归算了一下,组合有40375394种。用时64秒左右(把打印部分注释掉了),这个应该没有什么算法,只能递归吧?

        private static int iGroupCnt = 0;
        private static int[] arrSum;
        private static int[] arrFloorSum;

        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            int[] arrABC = new int[] { 54, 257, 19, 360 };
            int V = 654321;

            //存放x1x2x3x4
            int[] arrX = new int[arrABC.Length];

            //为了处理x1>x2>x3>x4的限定条件,加的2个数组
            arrSum = new int[arrABC.Length];
            arrFloorSum = new int[arrABC.Length];
            for (int i = 0; i < arrABC.Length; i++)
            {
                if (i > 0)
                {
                    arrSum[i] = arrSum[i - 1] + arrABC[i];
                    arrFloorSum[i] = arrFloorSum[i - 1] + arrSum[i - 1];
                }
                else
                {
                    arrSum[i] = arrABC[i];
                }
            }

            //当前处理的数的序号,右边的x值最小,从右边的数开始
            //序号
            int iCurIndex = arrABC.Length - 1;
            //值
            int iCur = arrABC[iCurIndex];
            //组合次数
            iGroupCnt = 0;
            //遍历函数
            IterateFun(arrABC, iCurIndex, arrX, V);

            ////如果考虑A1<=A,B1<=B,C1<=C,D1<=D的情况
            ////再外面加循环就行了,我给个嵌套的写法,你可以改成递归的方式,以适应ABC个数不确定
            //int[] arrABC2 = new int[arrABC.Length];
            //for (int i = 0; i < arrABC[0] + 1; i++)
            //{
            //    arrABC2[0] = i;
            //    for (int j = 0; j < arrABC[1] + 1; j++)
            //    {
            //        arrABC2[1] = j;
            //        for (int m = 0; m < arrABC[2] + 1; m++)
            //        {
            //            arrABC2[2] = m;
            //            for (int n = 0; n < arrABC[3] + 1; n++)
            //            {
            //                arrABC2[3] = n;
            //                IterateFun(arrABC2, iCurIndex, arrX, V);
            //            }
            //        }
            //    }
            //}

            sw.Stop();
            Console.WriteLine("组合数:" + iGroupCnt);
            Console.WriteLine("花费:"+sw.ElapsedMilliseconds+"毫秒");

            Console.ReadLine();
        }

        /// <summary>
        /// 递归函数
        /// </summary>
        /// <param name="arrABC">ABC数组</param>
        /// <param name="iCurIndex">当前序号</param>
        /// <param name="arrX">x1x2数组</param>
        /// <param name="VRemain">V剩余值</param>
        private static void IterateFun(int[] arrABC, int iCurIndex, int[] arrX, int VRemain)
        {
            //当前序号对应的值
            int iCur = arrABC[iCurIndex];
            if (iCurIndex < 1)
            {
                //如果还剩下A没有计算,直接判断能否整除
                int iRemainder = VRemain % iCur;
                if (iRemainder == 0 )
                {
                    int iQuotient = VRemain / iCur;
                    arrX[iCurIndex] = iQuotient;
                    //输出到屏幕中
                    //string s = "";
                    //for (int i = 0; i < arrIn.Length; i++)
                    //{
                    //    s += string.Format("{0}*{1}+", arrIn[i], arrLoop[i]);
                    //}
                    //s = s.TrimEnd('+');
                    //Console.WriteLine(s);
                    iGroupCnt++;
                    
                }
            }
            else
            {    
                //如果x1x2不考虑为0的情况,请将此处改为1
                int iMinX = 0;

                //前N项ABC之和
                int iSum = arrSum[iCurIndex];
                //因为x1>x2>x3>x4的限定,所以当计算x4时要减去(3x1+2x2+x3)
                int iFloorSum = arrFloorSum[iCurIndex];
                int iVRemainTmp = VRemain - iFloorSum;

                //考虑x1>x2>x3>x4限定后,X的最大取值,包括此最大值
                int iMaxX = iVRemainTmp / iSum;

                //当前X最小值不能比后面的X小
                if (iCur < arrX.Length - 1)
                {
                    iMinX = arrX[iCurIndex + 1] + 1;
                }

                for (int i = iMinX; i < iMaxX + 1; i++)
                {
                    arrX[iCurIndex] = i;
                    //遍历
                    IterateFun(arrABC, iCurIndex - 1, arrX, VRemain - i * iCur);
                }
            }
        }
只考虑A1=A,B1=B,C1=C,D1=D就大打折扣了吗。
Regan-lin 2013-10-24
  • 打赏
  • 举报
回复
真不好搞,全都是未知的数,而且还要是4个数才是一个组合一个解,真有这样的算法吗? Mark下先
  • 打赏
  • 举报
回复
引用 6 楼 reenjie 的回复:
單單這些條件還不夠吧,數字的正負或者數字為整型還是浮點型都沒有明確說明。
不好意思,所有数字都是正整数,可以是0。 A、B 、C、 D……这些数字至少有3个
火拼阿三 2013-10-24
  • 打赏
  • 举报
回复
我表示看的头疼。。。。
reenjie 2013-10-24
  • 打赏
  • 举报
回复
單單這些條件還不夠吧,數字的正負或者數字為整型還是浮點型都沒有明確說明。
加载更多回复(4)

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧