求1~35之间任意6个不重复的数字相加等于N的所有组合集。
单组数据中的数字按照升序排列。1 2 3 4 5 6
2 1 3 4 6 5
这样的分组视为重复

解决方案 »

  1.   

    呵呵,你只要能说动CSDN把分数值改成RMB,没问题
      

  2.   

    步骤1.1-35个数字排序取,当然必不可少的是6层循环,每层循环的开始数要比前一个大,例如
    for(int i = 1; i <= 35-6; i++)
    {
       for (int j = i + 1;j <=35-5;j++)
       {
         ......
       }
    }
    步骤2.判断六个数相加的结果等于你要求的数字N,记录最后个数,记为K
    K为所求
      

  3.   

    刚才有点错误,下面是代码
                const int N = 21;            int count = 0;
                for (int i = 1; i <= 35-5; i++)
                {
                    for (int j = i+1; j <= 35-4; j++)
                    {
                        for (int k = j + 1; k <=35-3;k++)
                        {
                            for (int l=k+1;l<=35-2;l++)
                            {
                                for (int m = l +1 ; m <= 35-1; m++)
                                {
                                    for (int n = m + 1; n <=35 ; n++)
                                    {
                                        if ( i + j + k + l + m + n == N)
                                        {
                                            count++;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
      

  4.   

    从1+2+3+4+5+6=21
    到29+31+32+33+34+35=224
    做一个循环列中中间的所有数 
    因这6个数相加和从 21到224
    比如任意组合和数为N N>=21&&N<224则N+1肯定有相应的组合数存在 所以21到224之间的数都打出来就可以了
     
      

  5.   

    用回溯写了一个
    感觉应该有更好的方法解决class Program
        {
            public static void Main(string[] args)
            {
                testMethod(35, 6, 30);
                System.Console.ReadLine();
            }        //三个参数分别表示               最大数字 几个数字     总和
            public static void testMethod(int maxNum, int count, int sum)
            {
                int[] result = new int[count];
                innerExcu(maxNum, 1, count, sum, result, 0, count);
            }        private static void innerExcu(int maxNum, int minNum, 
                int count, int sum, int[] result, int index, int reCou)
            {
                if (count == 0)
                {
                    if (sum == 0)
                    {
                        for (int i = 0; i < reCou; i++)
                        {
                            System.Console.Write(result[i] + " ");
                        }
                        System.Console.WriteLine();
                    }
                    else
                    {
                        return;
                    }
                }
                for (int i = minNum; i <= maxNum; i++)
                {
                    if (i > sum)
                        break;
                    result[index] = i;
                    innerExcu(maxNum, i + 1, count - 1, sum - i, result, index + 1, reCou);
                }
            }
        }
      

  6.   

    再发下 上边方法参数有一个是多余的
    class Program
        {
            public static void Main(string[] args)
            {
                testMethod(35, 6, 30);
                System.Console.ReadLine();
            }        //三个参数分别表示               最大数字        几个数字     总和
            public static void testMethod(int maxNum, int count, int sum)
            {
                int[] result = new int[count];
                innerExcu(maxNum, 1, count, sum, result, 0);
            }        private static void innerExcu(int maxNum, int minNum, 
                int count, int sum, int[] result, int index)
            {
                if (count == 0)
                {
                    if (sum == 0)
                    {
                        for (int i = 0; i < result.Length; i++)
                        {
                            System.Console.Write(result[i] + " ");
                        }
                        System.Console.WriteLine();
                    }
                    else
                    {
                        return;
                    }
                }
                for (int i = minNum; i <= maxNum; i++)
                {
                    if (i > sum)
                        break;
                    result[index] = i;
                    innerExcu(maxNum, i + 1, count - 1, sum - i, result, index + 1);
                }
            }
        }
      

  7.   

    发现了一个规律,发出来大家验证计算下。
    对于1-35,六数之和最小为21;最大为:195;
    而对于21到26=(21+6-1),每个数字只有唯一的6个数对应,即为:1+2+3+4+5+(6到11);
    26以后,则会有:
    27:
    1+2+3+4+5+12
    2+3+4+5+6+7
    28:
    1+2+3+4+5+13;
    2+3+4+5+7+7(error!28是个例外)
    29:
    1+2+3+4+5+14
    2+3+4+5+6+9
    2+3+4+5+7+8
    .
    .
    .
    (中间有一个临界值,可能是(21+195)/2左右,没算,有兴趣的算算,上了一天课头痛。)
    .
    .
    .
    165:{……}
    166到195只有一组对应。
      

  8.   


    123 124 125 126 127 128 129
    134 135 136 137 138 139
    145 146 147 148 149
    156 157 158 159
    167 168 169
    178 179
    189234 235 236 237 238 239
    245 246 247 248 249
    256 257 258 259
    267 268 269
    278 279
    289以上为分析示例数据推论.       
    /// <summary>
            /// 
            /// </summary>
            /// <param name="minnum">最小起始值</param>
            /// <param name="maxnum">最大起始值</param>
            /// <param name="count">匹配总值</param>
            /// <param name="num">数据位数</param>
            /// <param name="row">得到匹配第一个数据所在行数</param>
            /// <param name="index">得到匹配第一个数据所在行的列数</param>
            private void GetRowIndex(int minnum, int maxnum, int count, int num, out int row, out int index)
            {
                row = index = -1;//设置初始值为假设找不到数据.
                int mincount = (int)((minnum * 2 + num - 1) / 2.0 * num);//得到第一行最小值
                int maxcount = (int)((minnum * 2 + (num - 2)) / 2.0 * (num - 1)) + maxnum;//得到第一行最大值
                if (count >= minnum && count <= maxnum)
                {
                    int rowcount = maxnum - (minnum + num - 1);//得到总行数
                    index = count - mincount;//得到匹配数据在此区域的第一个位置值
                    row = 0;
                    if (index > rowcount)//当索引大于第一行所能列时.匹配查找第一个出现此索引的行数
                    {
                        row = index - rowcount;//得到第一个出现此索引的行数
                        index = rowcount - row;//得到索引在此行的真实列值
                    }
                }
            }通过此方法计算得到当前区域块的数据后.即可快速过滤出位置.然后通过此上面示例规则获取所在位置数据.
    下班了.有兴趣的可以完善一下.晚上回去再补充.
      

  9.   

    if (count >= minnum && count <= maxnum)
    替换成
     if (count >= mincount && count <= maxcount)这方法仅针对三位数的计算.超出三位后需要另加一参数指定第几位递增变化.然后针对修改一下mincount 与maxcount 的计算即可.
    思路一样..今晚没时间写了.改天抽空再补充.
      

  10.   

    终于有点空.按上面思路重新修改一下.写了下面方法.即可得到上面列出规则的三角区域块的匹配值.剩下的就是如何排列FirstData的算法啦.得到如123 ,234等或者更多位的FirstData数据后.然后套用下面方法即可. private List<int[]> GetData(int[] FirstData, int maxnum, int sum)
            {
                List<int[]> result = new List<int[]>();
                if (FirstData.Length < 2)//当组合位数小于2位时,此方法不适用
                { return result; }
                int mincount = 0;//当前区域最小和值
                int maxcount = 0;//当前区域最大和值
                int lineIndex = 0;//第一个匹配项所在行索引值
                int columnIndex = -1;//第一个匹配项所在列索引值
                int lineCount = -1;//当前区域总行数,为方便计算这里由0开始.即当lineCount=5时.实际行数为6行.
                for (int i = 0; i < FirstData.Length; i++)
                {
                    mincount += FirstData[i];//得到当前区域最小值
                }
                maxcount = mincount + 2 * maxnum - 2 * FirstData[FirstData.Length - 1];//得到当前区域最大值
                if (sum >= mincount && sum <= maxcount)//在这个区间有数据
                {
                    lineCount = (maxcount - mincount) / 2;//得到当前区域总行数,为方便计算这里由0开始.即当lineCount=5时.实际行数为6行.
                    columnIndex = sum - mincount;//得到匹配数据在此区域的第一个位置值
                    if (columnIndex > lineCount)//当索引大于第一行所能列时.匹配查找第一个出现此索引的行数
                    {
                        lineIndex = columnIndex - lineCount;//得到第一个出现此索引的行数
                        columnIndex = lineCount - lineIndex;//得到索引在此行的真实列值
                    }
                    for (int i = lineIndex; i <= lineCount && columnIndex >= 0; i++)
                    {
                        for (; columnIndex >= 0; columnIndex -= 2)//获取匹配值直到列小于0
                        {
                            int[] data = new int[FirstData.Length];
                            if (result.Count == 0)
                            {
                                FirstData.CopyTo(data, 0);//第一次获取匹配数据时.直接从FirstData值转换
                                data[data.Length - 1] += columnIndex;//添加匹配的列值
                                data[data.Length - 2] += lineIndex;//添加匹配的行值
                                result.Add(data);
                            }
                            else
                            {
                                result[result.Count - 1].CopyTo(data, 0);//后面的从上一个获取,并以行递增,列递减的形式获取匹配值
                                data[data.Length - 1] -= 1;//列递减
                                data[data.Length - 2] += 1;//行递增
                                result.Add(data);//得到新的匹配值
                            }
                        }
                    }
                }
                return result;
            }
      

  11.   

    晕.居然不能发贴了.马甲来也!!哈哈.
    咋就没人关注这题呢..
    修正上面一小BUG.
    data[data.Length - 1] += columnIndex;//添加匹配的列值
    替换成
    data[data.Length - 1] += columnIndex + lineIndex;//添加匹配的列值
    虽然能实现查找.但仍不够高效.就不继续完善了.下面发个更高效的.
      

  12.   


    /// <summary>
            /// 获取N位(n>=2)不重复的匹配总值组合结果值
            /// </summary>
            /// <param name="minnum">最小开始数值</param>
            /// <param name="maxnum">最大结束数值</param>
            /// <param name="digits">组合位数</param>
            /// <param name="sum">匹配组合总值</param>
            /// <returns>得到匹配的组合集合</returns>
            private List<int[]> GetData(int minnum, int maxnum, int digits, int sum)
            {
                List<int[]> result = new List<int[]>();
                if (digits < 2)//当组合位数小于2位时,此方法不适用
                { return result; }
                int[] firstData = new int[digits];
                int minsum = 0;
                for (int i = 0; i < firstData.Length - 1; i++)//得到第一项匹配值的最小起始数据
                {
                    firstData[i] = i + minnum;
                    minsum += firstData[i];
                }
                firstData[firstData.Length - 1] = sum - minsum;//得到第一项匹配值的最大结尾数据
                if (firstData[firstData.Length - 1] - firstData[firstData.Length - 2] > 0)//如果此第一项数据能正常匹配成功则开始补值位移下一个数据.
                {
                    int n = digits - 2;//补值位数
                    result.Add((int[])firstData.Clone());//添加第一个匹配项
                    while (firstData[firstData.Length - 1] - firstData[firstData.Length - 2] > 1)//循环位移补值至最后一位比倒数第二位大于1.
                    {
                        firstData[firstData.Length - 1] -= 1;
                        firstData[n--] += 1; //补值为由后位位置往前推
                        n = n < 0 ? digits - 2 : n;//当位置小于0时则返回从新从倒数第二位开始补值.
                        result.Add((int[])firstData.Clone());//把新得到的值副本添加到集合中
                    }
                }
                return result;
            }
    List<int[]> result = GetData(1, 35, 6, 50);
    获取结果
    1,2,3,4,5,35
    1,2,3,4,6,34
    1,2,3,5,6,33
    1,2,4,5,6,32
    1,3,4,5,6,31
    2,3,4,5,6,30
    2,3,4,5,7,29
    2,3,4,6,7,28
    2,3,5,6,7,27
    2,4,5,6,7,26
    3,4,5,6,7,25
    3,4,5,6,8,24
    3,4,5,7,8,23
    3,4,6,7,8,22
    3,5,6,7,8,21
    4,5,6,7,8,20
    4,5,6,7,9,19
    4,5,6,8,9,18
    4,5,7,8,9,17
    4,6,7,8,9,16
    5,6,7,8,9,15
    5,6,7,8,10,14
    5,6,7,9,10,13
    5,6,8,9,10,12
    5,7,8,9,10,11
      

  13.   


    /// <summary>
            /// 获取N位(n>=2)不重复的匹配总值组合结果值
            /// </summary>
            /// <param name="minnum">最小开始数值</param>
            /// <param name="maxnum">最大结束数值</param>
            /// <param name="digits">组合位数</param>
            /// <param name="sum">匹配组合总值</param>
            /// <returns>得到匹配的组合集合</returns>
            private List<int[]> GetData(int minnum, int maxnum, int digits, int sum)
            {
                List<int[]> result = new List<int[]>();
                if (digits < 2)//当组合位数小于2位时,此方法不适用
                { return result; }
                int[] firstData = new int[digits];
                int minsum = 0;
                for (int i = 0; i < firstData.Length - 1; i++)//得到第一项匹配值的最小起始数据
                {
                    firstData[i] = i + minnum;
                    minsum += firstData[i];
                }
                firstData[firstData.Length - 1] = sum - minsum;//得到第一项匹配值的最大结尾数据
                int n = digits - 2;//补值位数
                while (firstData[firstData.Length - 1] > maxnum && //当最大结尾数据大于最大值时,同样使用位移补值直至符合初始最大值.
                    firstData[firstData.Length - 1] - firstData[firstData.Length - 2] > 0)//当倒数第一位小于等于倒数第二位时没有匹配数据.直接跳出循环.
                {
                    firstData[firstData.Length - 1] -= 1;
                    firstData[n--] += 1; //补值为由后位位置往前推
                    n = n < 0 ? digits - 2 : n;//当位置小于0时则返回从新从倒数第二位开始补值.
                }
                if (firstData[firstData.Length - 1] - firstData[firstData.Length - 2] > 0)//如果此第一项数据能正常匹配成功则开始补值位移下一个数据.
                {
                    n = digits - 2;//补值位数
                    result.Add((int[])firstData.Clone());//添加第一个匹配项
                    while (firstData[firstData.Length - 1] - firstData[firstData.Length - 2] > 1)//循环位移补值至最后一位比倒数第二位大于1.
                    {
                        firstData[firstData.Length - 1] -= 1;
                        firstData[n--] += 1; //补值为由后位位置往前推
                        n = n < 0 ? digits - 2 : n;//当位置小于0时则返回从新从倒数第二位开始补值.
                        result.Add((int[])firstData.Clone());//把新得到的值副本添加到集合中
                    }
                }
                return result;
            }
    修正当sum大于maxnum时会超出最大值错误.真粗心~~唉!!!!!
      

  14.   

    while (firstData[firstData.Length - 1] - firstData[firstData.Length - 2] > 1)//循环位移补值至最后一位比倒数第二位大于1.
    替换成
    while (firstData[firstData.Length - 1] - firstData[firstData.Length - 2] > 2)//循环位移补值至最后一位比倒数第二位大于1.
    真粗心~~唉!!!!!真要命.唉......
      

  15.   

    你代码求的数很明显的有丢失
    class Program
        {
            public static void Main(string[] args)
            {
                testMethod(35, 6, 50);
                System.Console.ReadLine();
            }        public static void testMethod(int maxNum, int count, int sum)
            {
                int[] result = new int[count];
                innerExcu(maxNum, 1, count, sum, result);
            }        private static void innerExcu(int maxNum, int minNum, 
                int count, int sum, int[] result)
            {
                if(count * maxNum - (count - 1) * count / 2 < sum)
                    return;
                for (int i = minNum; i <= maxNum - count + 1; i++)
                {
                    if (count * i + (count - 1) * count / 2 > sum)
                        return;
                    if (count * i + (count - 1) * count / 2 == sum)
                    {
                        for (int a = 0; a < result.Length - count; a++)
                        {
                            Console.Write(result[a] + " ");
                        }
                        for (int b = 0; b < count; b++)
                        {
                            Console.Write(i + b + " ");
                        }
                        Console.WriteLine();
                        return;
                    }
                    if (count == 2)
                    {
                        if (sum - i <= maxNum)
                        {
                            result[result.Length - 2] = i;
                            result[result.Length - 1] = sum - i;
                            for (int a = 0; a < result.Length; a++)
                            {
                                Console.Write(result[a] + " ");
                            }
                            Console.WriteLine();
                        }
                        continue;
                    }
                    result[result.Length - count] = i;
                    innerExcu(maxNum, i + 1, count - 1, sum - i, result);
                }
            }
        }
      

  16.   

    我在楼上的代码复制化了 
    下边这个优化了下
    每次递归进行时,
    当前选择的数或是一个解,当不是一个解的时候,在后边递归调用的方法必会随即退出
    class Program
        {
            public static void Main(string[] args)
            {
                testMethod(35, 6, 180);
                System.Console.ReadLine();
            }        public static void testMethod(int maxNum, int count, int sum)
            {
                int[] result = new int[count - 2];
                innerExcu(maxNum, 1, count, sum, result);
            }        private static void innerExcu(int maxNum, int minNum, 
                int count, int sum, int[] result)
            {
                int star = sum - maxNum * count + maxNum + (count - 2) * (count - 1)/2;
                star = star > minNum ? star : minNum;
                int end = maxNum - count + 1;
                for (int i = star; i <= end; i++)
                {
                    if (count == 2)
                    {
                        if (2 * i < sum)
                        {
                            for (int j = 0; j < result.Length; j++)
                            {
                                Console.Write(result[j] + " ");
                            }
                            Console.WriteLine(i + " " + (sum - i));
                        }
                        continue;
                    }
                    result[result.Length - count + 2] = i;
                    innerExcu(maxNum, i + 1, count - 1, sum - i, result);
                }
            }
        }
      

  17.   


    /// <summary>
            /// 获取N位(n>=2)不重复的匹配总值组合结果值
            /// </summary>
            /// <param name="data">当前数据</param>
            /// <param name="minnum">最小起始数值</param>
            /// <param name="maxnum">最大结束数值</param>
            /// <param name="sum">匹配组合总值</param>
            /// <param name="index">当前匹配位置索引</param>
            /// <returns>得到匹配的组合集合</returns>
            private List<int[]> GetData(int[] data, int minnum, int maxnum, int sum, int index)
            {
                List<int[]> result = new List<int[]>();
                int newminnum = sum - (int)((maxnum + maxnum - (data.Length - index - 2)) / 2.0 * ((data.Length - index) - 1));
                minnum = newminnum > minnum ? newminnum : minnum;//计算获取第一个最小起始值
                for (int i = minnum; i <= maxnum; i++)
                {
                    if (sum - i > (int)((i + 1 + i + (data.Length - index - 2)) / 2.0 * ((data.Length - index) - 1)))//当前总值减去索引位置值仍大于后一位以后的最小总值,则仍可执行下一步匹配计算。
                    {
                        data[index] = i;
                        if (index == data.Length - 2)
                        {
                            if (sum - i <= maxnum)//最后一位时,如果小于最大限制值则成功匹配
                            {
                                data[index + 1] = sum - i;
                                result.Add((int[])data.Clone());
                            }
                            else//否则后面也没有了。可跳出此次循环。
                            {
                                break;
                            }
                        }
                        else
                        {
                            result.AddRange(GetData(data, i + 1, maxnum, sum - i, index + 1).ToArray());//开始计算一下位的数据。
                        }
                    }
                    else//后最小面值已经无法支持当前索引位置值继续增加。因此跳出此次循环
                    {
                        break;
                    }
                }
                return result;
            }
    终于有空。再写一个!
      

  18.   

    调用
    List<int[]> result = GetData(new int[6], 1, 35, 50, 0);晕看了一下#36楼的。惭愧了~!思路跟他的一样的,。膜拜一下!!呵呵就当是我学习他的思路写的另一种写法吧。
      

  19.   

    令总和为X,则所求6个数中最大的一个
    maxValue < Math.Min(35, x-15)
    maxValue > Math.Truncate((x+15)/6) + 1最小的一个
    minValue < Math.Truncate((x-15)/6)也许对改进算法有用
      

  20.   


            /// <summary>
            /// 获取N位(n>=2)不重复的匹配总值组合结果值
            /// </summary>
            /// <param name="data">当前数据</param>
            /// <param name="minnum">最小起始数值</param>
            /// <param name="maxnum">最大结束数值</param>
            /// <param name="sum">匹配组合总值</param>
            /// <param name="index">当前匹配位置索引</param>
            /// <returns>得到匹配的组合集合</returns>
            private List<int[]> GetData(int[] data, int minnum, int maxnum, int sum, int index)
            {
                List<int[]> result = new List<int[]>();
                int newminnum = sum - (int)((maxnum + maxnum - (data.Length - index - 2)) / 2.0 * ((data.Length - index) - 1));
                minnum = newminnum > minnum ? newminnum : minnum;//计算获取第一个最小起始值
                for (int i = minnum; i <= maxnum && sum - i > (int)((i + 1 + i + (data.Length - index - 2)) / 2.0 * ((data.Length - index) - 1)); i++)
                {
                    data[index] = i;
                    if (index == data.Length - 2)
                    {
                        data[index + 1] = sum - i;
                        result.Add((int[])data.Clone());
                    }
                    else
                    {
                        result.AddRange(GetData(data, i + 1, maxnum, sum - i, index + 1).ToArray());//开始计算一下位的数据。
                    }
                }
                return result;
            }优化一下.减少三百多次的循环break浪费..这次算是最优解了吧!!