user-0 提问: 分班

回复:
user: user-1
content: 此题要问小学老师，博士未必打得出，

user: user-2
content: 引用 14 楼 u014444402 的回复:看了各位的回复，思路都是逐个的平衡，但是这样的话会出现某种组合会比我们逐个平衡的小。 所以我觉得应该在分班后调整，即先随便分，然后再两个班中调整，但是如何调整？目前还没好想法。  试下这种； 先随便分并对两个班排序，然后看两个班总分数相差多少，比如相差20分 然后找将两个班中差值最接近20的一组进行调换 重复这个过程直到总分差值不再减小

user: user-3
content: 人数要一样？ 那就看这个 http://www.cppblog.com/baby-fly/archive/2009/09/24/92392.html

user: user-0
content: 引用 23 楼 Rewen 的回复:我的思路    1， 先算平均值 av   2， 各个分数 - av 得到 差值  var   3， 设置2个Flag ， FlagA = FlagA + var , FlagB = FlagB + var   4， 在var list中取得值，是FlagA 和FlagB 都接近于0. 有无伪代码?看得不是很明白.

user: user-3
content: 这是个0/1背包问题，可以用动态规划搞，看这里 http://blog.csdn.net/pegasuswang_/article/details/25081783

user: user-0
content: 引用 25 楼 lqbk1 的回复:人数要一样？ 那就看这个 http://www.cppblog.com/baby-fly/archive/2009/09/24/92392.html 嗯,很精彩的讲解.多谢.   引用 26 楼 paschen 的回复:[quote=引用 14 楼 u014444402 的回复:] 看了各位的回复，思路都是逐个的平衡，但是这样的话会出现某种组合会比我们逐个平衡的小。 所以我觉得应该在分班后调整，即先随便分，然后再两个班中调整，但是如何调整？目前还没好想法。  试下这种； 先随便分并对两个班排序，然后看两个班总分数相差多少，比如相差20分 然后找将两个班中差值最接近20的一组进行调换 重复这个过程直到总分差值不再减小[/quote] 我刚开始就是这样想的, 但是问题就在这个"组"上了,一组是1个数字,2个?还是好几个,到底是哪几个..好像又引进组合了.

user: user-4
content: 我的思路    1， 先算平均值 av   2， 各个分数 - av 得到 差值  var   3， 设置2个Flag ， FlagA = FlagA + var , FlagB = FlagB + var   4， 在var list中取得值，是FlagA 和FlagB 都接近于0.

user: user-5
content: N有取值范围吗？

user: user-0
content: 引用 15 楼 qq_29120981 的回复:两个班总分之差最小,即两个班总分都是接近(所有学生成绩总分和)/2,然后贪心 怎么贪?具体一点?有伪代码最好.

user: user-6
content: 两个班总分之差最小,即两个班总分都是接近(所有学生成绩总分和)/2,然后贪心

user: user-5
content: 仅供参考：//给出12个随机数,分成三组求和,每组的个数不定,要求求出来的三个数之间相差最小,最完美的情况是三个数相等. #include <stdlib.h> #include <stdio.h> #include <time.h> #include <math.h> #include <limits.h> int i,j,k; int g[12][3]={//可能的分组大小     { 1, 1,10},     { 1, 2, 9},     { 1, 3, 8},     { 1, 4, 7},     { 1, 5, 6},     { 2, 2, 8},     { 2, 3, 7},     { 2, 4, 6},     { 2, 5, 5},     { 3, 3, 6},     { 3, 4, 5},     { 4, 4, 4}, }; int n[12]; int m[12]; int f[12];//当前最小时各数 int g1,g2,g3;//1,2,3组可分配的个数 int n1,n2,n3;//1,2,3组已分配的个数 int f1,f2;//当前最小时1,2组的个数 int s1,s2,s3;//123组的和 int d;//1-2,2-3,3-1组中各数和之间差的绝对值之和 int dmin=INT_MAX;//保存当前d的最小值 void swap(int *pi1,int *pi2) {     int t;     t=*pi1;*pi1=*pi2;*pi2=t; } void test() {     s1=0;     for (i=0;i<g1;i++) s1=s1+n[i];     s2=0;     for (i=g1;i<g1+g2;i++) s2=s2+n[i];     s3=0;     for (i=g1+g2;i<12;i++) s3=s3+n[i];     d=abs(s1-s2)+abs(s2-s3)+abs(s3-s1);     if (d<dmin) {         dmin=d;         f1=g1;         f2=g2;         for (i=0;i<12;i++) f[i]=n[i];         printf("(");         for (i=0;i<g1;i++) printf("%2d,",n[i]);         printf(")  (");         for (i=g1;i<g1+g2;i++) printf("%2d,",n[i]);         printf(")  (");         for (i=g1+g2;i<12;i++) printf("%2d,",n[i]);         printf(") %4d\n",dmin);     } else {         printf("(");         for (i=0;i<g1;i++) printf("%2d,",n[i]);         printf(")  (");         for (i=g1;i<g1+g2;i++) printf("%2d,",n[i]);         printf(")  (");         for (i=g1+g2;i<12;i++) printf("%2d,",n[i]);         printf(") %4d\n",d);     } } void main() {     srand(time(NULL));     for (i=0;i<12;i++) m[i]=rand()%100;     for (i=0;i<12;i++) printf("%2d,",m[i]);     printf("\n");     for (i=1;i<12;i++) {         for (j=0;j<i;j++) {             if (m[i]>m[j]) swap(&m[i],&m[j]);//冒泡排序从大到小         }     }     for (i=0;i<12;i++) printf("%2d,",m[i]);     printf("\n");     for (k=0;k<12;k++) {//在12种分组方法中         //取第i种分组方法         g1=g[k][0];         g2=g[k][1];         g3=g[k][2];         printf("%2d-%2d,%2d,%2d\n",k,g1,g2,g3);         //将从大到小12个数双向轮流分配到三个组中         n1=0;         n2=0;         n3=0;         for (j=0;j<12;j++) {             switch (j%6) {             case 0:         redo:                 if (n1<g1) {                     n[n1]=m[j];                     n1++;                     break;                 }             case 1:                 if (n2<g2) {                     n[g1+n2]=m[j];                     n2++;                     break;                 }             case 2:                 if (n3<g3) {                     n[g1+g2+n3]=m[j];                     n3++;                     break;                 }             case 3:                 if (n3<g3) {                     n[g1+g2+n3]=m[j];                     n3++;                     break;                 }             case 4:                 if (n2<g2) {                     n[g1+n2]=m[j];                     n2++;                     break;                 }             case 5:                 if (n1<g1) {                     n[n1]=m[j];                     n1++;                     break;                 }             default:goto redo;             }         }         test();     }     printf("---------------------------------------------------\n");     g1=f1;     g2=f2;     for (i=0;i<12;i++) n[i]=f[i];     printf("(");     for (i=0;i<g1;i++) printf("%2d,",n[i]);     printf(")  (");     for (i=g1;i<g1+g2;i++) printf("%2d,",n[i]);     printf(")  (");     for (i=g1+g2;i<12;i++) printf("%2d,",n[i]);     printf(") %4d\n",dmin); }

user: user-0
content: 引用 20 楼 zhao4zhong1 的回复:[quote=引用 19 楼 zhao4zhong1 的回复:] N为1时，…… https://www.baidu.com/s?wd="一班就两个学生"[/quote]  引用 19 楼 zhao4zhong1 的回复:N为1时，…… 不要捣乱.

user: user-5
content: 引用 19 楼 zhao4zhong1 的回复:N为1时，…… https://www.baidu.com/s?wd="一班就两个学生"

user: user-5
content: N为1时，……

user: user-0
content: 再加100分,求解答.

user: user-0
content: 看了各位的回复，思路都是逐个的平衡，但是这样的话会出现某种组合会比我们逐个平衡的小。 所以我觉得应该在分班后调整，即先随便分，然后再两个班中调整，但是如何调整？目前还没好想法。

user: user-7
content: 有点意思好 哈哈

user: user-8
content: 看了下各楼的回复。我自己总结了个想法，经过手动举例验证还是不对的，先想到这里了，先贴出来。  （1）求出2N个同学成绩的平均值，记为变量average； （2）对2N个铜须的成绩进行排序，从小到大，和从大到小都可以； （3）选出2N个数（2N个同学的的成绩），离平均值最近的两个数，比如说是x1，x2。           把x1,x2任意分配到对应的A班和B班，比如分数为x1对应的同学分到A班，分数为x2对应的同学分配到B版。 （4）选出距离平均值第二近的两个数，比如说是y1,y2。A班的成绩记为sumA，B班的成绩记为sumB。          如果把y1分配到A班，则A班现在的成绩是sumA = x1 + y1，B班现在的成绩是sumB = x2 + y2; 	 如果把y2分配到A班，则A班现在的成绩是sumA = x1 + y2，B班现在的成绩是sumB = x2 + y1; 	  	 如果((x1 + y1) - (x2 + y2))的绝对值 > ((x1 + y2) - (x2 + y1))的绝对值，则将分数y2对应的同学分配到A班，分数y1对应的同学分配到B班。 	 这样保证每班两个同学时，分数总和的差距是最小的。 （5）以此类推，保证每班多分一个学生时，分数总和的差距都是最小。  举个最简单的实例：4个同学（2N中的N=2），成绩分别是60,55,80,78。 （1）平均值是68.25； （2）排序结果是55,60,78,80; （3）离平均值最近的两个数是60,78; 60对应的同学分到A班，78对应的同学分到B班； （4）距离平均值第二近的两个数是55,80。|(60+55)-(78+80)| > |(60+80)-(78+55)|， 	故将55,78的同学分到A班，60,80的同学分到B班，这样成绩总差为7是最小的。 	 	但是（60 + 78） - （55 + 80） = 3，将60,78的同学分到A班，55,80的同学分配到B班分数差才是最小的…… 	所以最开始将60和78分开就是个bug……

user: user-9
content: 另一个办法 从最大分数开始，安插 保持两个班级的平衡 新安插的优先安插总分低的班级，总分相同，A，或者B优先安插（或者随机优先安插）

user: user-9
content: 先排序 然后按照最接近分数平均值，安排一个班即可