您的位置:首页 > 编程语言 > C语言/C++

拔河分组

2016-12-31 14:02 375 查看
有12个同学要分成两个组进行拔河比赛,为使比赛公平,分组时要求每组6个同学,且两组的体重之和相等;

已知这12个同学的体重分别为:38、39、47、35、46、58、51、42、36、40、59、39;

根据他们的体重(为方便计算以全部转化为整数,单位为kg)实施分组,若无法实现数据个数与数据和均相等的分组,标注为“无法均分”;

基本方法- -双均分法

1.说明:

我们把“要求每组数据个数相等数据和也相等”的分组称为双均分,最简单的双均分问题是把已知的4个数b1、b2、b3、b4分成两个组,问题的判断比较简单,把4个数排序,设b1< b2< b3< b4,只要判断b1+b4=b2+b3是否成立即可;

当涉及双均分的数据较多时,分组就变得比较复杂了;

从键盘输入(或随机产生)的12个正整数存储在b数组中,求出总和s,若和s为奇数,显然无法分成重量相等的两组,提示后退出;若s为偶数,则s1=s/2;

为方便调整,设置数组a存储b数组的下标值,即a(i):1~12;

考察b(1)所在的组,只要另从b(2)~b(12)中选取5个数,即定下a(1)=1,其余的a(i)(i=2,……,6)在2~12中取不重复的数,因为组合与顺序无关,不妨设:

2<=a(2)< a(3)<……< a(6)<=12

从a(2)取2开始,以后a(i)从a(i-1)+1开始递增1取值,对a(2)~a(6)设置5重循环,这样可避免重复又不至于遗漏;

在内循环中,计算s=b(1)+b(a(2))+……+b(a(6)),若s=s1,满足要求,实现平分;

对输入的12个整数并不总有解,有解时,找到并输出所有的解,没有解时,显示相关提示信息“无法实现平分”;

2.程序设计:

#include<stdio.h>
#include<math.h>
#include<time.h>
int main()
{
int j,k,m,a[7],b[13];
long t,s1,s=0;
t=time(0)%1000;
srand(t);        /*随机数发生器初始化*/
printf("已知12个同学的体重分别为:\n");
for(s=0,k=1;k<=12;k++)      /*输入12个整数*/
{
s+=b[k]=rand()%25+35;
printf("%d",b[k]);
}
if(s%2==0)
{
printf("\n以上12个整数总和为%d \n",s);
s1=s/2;
}
else
{
printf("和为奇数,无法平分!\n");
}
a[1]=1;
m=0;
for(a[2]=2;a[2]<=8;a[2]++)
for(a[3]=a[2]+1;a[3]<=9;a[3]++)
for(a[4]=a[3]+1;a[4]<=10;a[4]++)
for(a[5]=a[4]+1;a[5]<=11;a[5]++)
for(a[6]=a[5]+1;a[6]<=12;a[6]++)
{
for(s=0,k=1;k<=6;k++)
s=s+b[a[k]];
if(s==s1)           /*满足均分条件时输出*/
{
m++;
printf("NO%d:",m);
for(j=1;j<=6;j++)
printf("%d",b[a[j]]);
printf("\n");
}
}
if(m>0)
printf("共有以上%d种分发\n",m);
else
printf("无法实现二维均分\n");
}


3.程序运行示例:

已知12个同学的体重分别为:
38 39 47 35 46 58 51 42 36 40 59 39
以上12个整数总和为530
NO 1:38 39 47 46 36 59
NO 2:38 39 47 42 40 59
......
NO 15:38 51 42 36 59 39
共有以上种分发


双均法拓广

一般地,对已知的2n(n从键盘输入)个正整数,试把这些数分为2组,每组n个数,且每组数据的和相等或两组数据和相差最小;

这里把分2组的数据个数一般化为2n个,每组n个数据要求不变,若能分成每组数据和相等,则输出所有不同的分发;若不能分成每组数据和相等,则求出两组数据和相差最小的分组;

1.说明:

求解拓广的双均分问题要求更高了,可采用回溯法逐步实施调整;

1)、回溯实施

对于已有的存储在b数组中的2n个正整数(随机产生或键盘输入均可),求出总和s及其和的一半s1(若这2n个数的和s为奇数,则s1=s/2非整数);

把这2n个数分成2组,每组n个数,为方便调整,设置数组a存储b数组的下标值,即a(i):1~2n

考察b(1)所在的组,只要另从b(2)~b(2n)中选取n-1个数,即定下a(1)=1,其余的a(i)(i=2,……,n)在2~2n中取不重复的数,因为组合与顺序无关,不妨设: 2<=a(2)< a(3)<……< a(n)<=2n ;

从a(2)取2开始,以后a(i)从a(i-1)+1开始递增1取值,直至n+i为止,这样可避免重复;

2)、双均分判断

若s2!=s1,则a(n)继续增1再试,如果a(n)已增至2n,则回溯前一个a(n-1)增1再试,如果a(n-1)已增至2n-1,继续回溯,直至a(2)增至n+2时,结束;

3)、无法双均分处理

双均分问题并不总能实现,例如当总和s为奇数时显然无法双均分,就是s为偶数,也不一定能实现双均分;

对于不能实现双均分的情形,同样应用回溯探求“两组数据和相差最小”的分组:当a(n)已取值时,计算s2=b(1)+b(a(2))+……b(a(n)),d=|s2-s1|;在d与min比较中求取d的最小值,并用s3记录最小时的n个数据和,用c数组记录此时的下标数组a的值

回溯完成后,输出两组数据和相差最小2*min,并据c数组输出分组的一组数据;

2.程序设计:

#define N 50
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
int main()
{
int n,m,a
,c
,b[2*N],i,j,k,t;
long s2,s3,s=0;
double d,s1,min=1000;
t=time(0)%1000;
srand(t);          /*随机数发生器初始化*/
printf("请输入n:");
scanf("%d",&n);
printf("已知%d个同学的体重分别为:\n",2*n);
for(s=0,i=1;i<=2*n;i++)       /*产生2n个随机整数*/
{
s+=b[i]+rand()%25+30;      /*s为2n个整数之和*/
printf("%d",b[i]);
}
printf("\n以上%d个重量总和为%d\n",2*n,s);
s1=(double)s/2;               /*s2为探索过程中n个数据之和*/
i=1;
a[1]=1;
m=0;
while(s%2==0)
{
if(i==n)
{
for(s2=0,j=1;j<=n;j++)     /*s2为探索过程中n个数据之和*/
s2+=b[a[j]];
if(s1==(double)s2)         /*满足均分条件时输出*/
{
m++;
if(m<=3)
{
printf("NO%d:",m);
for(j=1;j<=n;j++)
printf("%d ",b[a[j]]);
printf("\n");
}
}
}
else
{
i++;
a[i]=a[i-1]+1;
continue;
}
while(a[i]==n+1)
i--;            /*调整或回溯*/
if(i>1)
a[i]++;
else
break;
}
if(m>0)
{
printf("\n共有以上%d种分法\n",m);
return;
}
else
{
printf("无法实现二组重量均分!\n");
i=1;
a[1]=1;
m=0;
while(1)
{
if(i==n)
{
for(s2=0,j=1;j<=n;j++)
s2+=b[a[j]];
d=fabs((double)s2-s1);
if(d<min)          /*d与min比较求取最小值*/
{
min=d;
s3=s2;
for(k=1;k<=n;k++)
c[k]=a[k];
}
}
else
{
i++;
a[i]=a[i-1]+1;

4000
continue;
}
while(a[i]==n+i)
i--;           /*调整或回溯*/
if(i>1)
a[i]++;
else
break;
}
printf("用以下分组可使得两组重量相差最小为%.0f:\n",2*min);
for(j=1;j<=n;j++)
printf("%d",b[c[j]]);
printf("\n该组重量为%d;余下为第2组,重量为%ld\n",s3,s-s3);
}
}


3.程序运行示例及其注意事项:

请输入n:10
已知20个同学的体重分别为:
31 39 54 30 42 49 44 35 41 36 49 33 48 32 49 49 39 48 43 38
以上20个重量总和为829
无法实现二祖重量均分!
用以下分组可使得两组重量相差最小为1:
31 39 54 30 42 49 44 35 41 49
该组重量为414;余下为第2组,重量为415


注意:

以上程序设计对两组均分只输出其中一个组,另一组省略输出,即为其余数组成;

如果在输出中出现有些解“重复”,这是由于2n个数据有重复(例如不同同学有相同的体重)造成的;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息