| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3610 人关注过本帖
标题:求高手编写一个将十个数分成五组的程序!
只看楼主 加入收藏
风居住的街道
Rank: 1
等 级:新手上路
帖 子:374
专家分:0
注 册:2008-10-24
收藏
得分:0 
[bo][un]广陵绝唱[/un] 在 2008-11-5 10:29 的发言:[/bo]

说实话,全排列的程序现在还没弄懂,网上看了不少,去某些Q群和论坛也去问过,可是到现在也没弄出个子午卯酉。如果你能详细讲解一下,感激不尽。


你先尝试一下嘛,不行的话,我再帖我的代码,m分成n组那个我还没搞定,因为貌似比较复杂……我用的动态二叉树的回溯做的……
2008-11-05 11:28
forever74
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:CC
等 级:版主
威 望:58
帖 子:1705
专家分:4345
注 册:2007-12-27
收藏
得分:0 
俺没有真的学过数据结构
所以只能用山寨解法:
m个互不相同的数平分成n组,那么每组有k=m/n个哈
不影响题意的简单假设这m个数就是从1到m,
这里边一定有一组包含了最小的那个(目前是1),这一组的构成有(从m-1个数中挑出k-1个的组合数)那么多种可能性;
对于上述每一种可能性,剩下的问题是将剩下的m-k个数平分成n-1组的问题,于是递归之。

做组合就更简单了,a个里面挑选b个的组合里面最小那个元素有a-b+1种可能性,然后就是递归到a-1个里面挑选b-1个的问题了。这个有很多现成的代码,拿来改改就成了。

对宇宙最严谨的描述应该就是宇宙其实是不严谨的
2008-11-05 14:02
scheelite
Rank: 1
等 级:新手上路
帖 子:45
专家分:0
注 册:2008-11-5
收藏
得分:0 
不会
2008-11-05 15:10
gzbao9999
Rank: 1
等 级:新手上路
威 望:1
帖 子:40
专家分:0
注 册:2008-11-5
收藏
得分:0 
//搞定了
//运行的结果为113400
//你想把打印的出来结果的话 把print函数里的printf语句 从//里放出来就行了
//打印的话 可能要打印很久
//这个程序是在 全排列的基础上 加控制
//就是保证 第偶数次选数比前一次大就行(小也可以,任选一种可能):注意我这的用词  第!!!
//因此有第2 4 6 8 10共5次需要控制 也就是 我们的结果应该是在全排列的基础上除以5次2,也就是除以32

//全排列的可能为10!= 3628800  除以32 刚好等于113400
程序如下:
--------------------------------------------------------
#include<stdio.h>

int array[10]={1,2,3,4,5,6,7,8,9,10};
int cache[10];
int time=0;

//------------------
select(int ceng,int mark1[],int sub)
{
    ceng++;
    int mark2[10];
    int i,j ;
    arraycopy(mark2,mark1);
    for(i=0;i<10;i++)
    {
        if(mark2[i]==0)
        continue ;
        if(mark2[i]==1){
                if(ceng%2!=0&&i<sub){
                continue;
                }
                mark2[i]=0 ;
                cache[ceng]=array[i];
                mark1[i]=0;
                if(ceng<9){
                    select(ceng,mark1,i);
                }
                if(ceng==9){
                    print();
                }
                mark1[i]=1;
        }
    }
}
//---------------------------
int arraycopy(int mark2[],int mark1[])
{
int i ;
for(i=0;i<10;i++)
{
    mark2[i]=mark1[i];
}
}
//---------------------------
print(mark2){
time++;
int i ;
for(i=0;i<10;i++)
{
    //printf("%d,",cache[i]);
}
//printf("\n");
}
//---------------------------
main()
{
  int ceng;
  ceng=-1;
  //mark[i]=0表示array[i]被选过了,不能再选择
  //mark[i]=1表示array[i]未被选过,可以选择
  int mark1[]={1,1,1,1,1,1,1,1,1,1};
  int sub=-1;
  select(ceng,mark1,sub);
  printf("time=%d\n",time);
}

[[it] 本帖最后由 gzbao9999 于 2008-11-5 17:41 编辑 [/it]]
2008-11-05 15:27
风居住的街道
Rank: 1
等 级:新手上路
帖 子:374
专家分:0
注 册:2008-10-24
收藏
得分:0 
[bo][un]forever74[/un] 在 2008-11-5 14:02 的发言:[/bo]

俺没有真的学过数据结构
所以只能用山寨解法:
m个互不相同的数平分成n组,那么每组有k=m/n个哈
不影响题意的简单假设这m个数就是从1到m,
这里边一定有一组包含了最小的那个(目前是1),这一组的构成有(从m-1 ...


不错,我就是这个思路!
2008-11-05 16:44
广陵绝唱
Rank: 10Rank: 10Rank: 10
等 级:贵宾
威 望:29
帖 子:3607
专家分:1709
注 册:2008-2-15
收藏
得分:0 
程序代码:
/***********************************************************************

    依样画葫芦,写了这个程序,不过还只是知其然而不知其所以然,对于它的
原理,为什么会完成这样的功能,还是不明白。另外,这个程序显然有些弊病,
因为是两个数为一组,那么对于2、3和3、2这样的一组,它就不能区分。

    由于对程序的原理弄不明白,所以也不知道这样的弊病怎样去修改。希望哪
位朋友帮忙解释一下,不胜感激。

***********************************************************************/
#include<stdio.h>
#include<string.h>   
#define N 11
int j=0;
void formturn(int index,char *s,char *mys)
{ 
    char s1[N];
    char tmp;
    int i;
    for(i=0;i<strlen(s);i++)
    { 
        tmp=s[i]; 
        mys[index]=s[i]; 
        s[i]=0; 
        strcpy(s1,s); 
        strcat(s1,&s[i+1]);
        s[i]=tmp;
        formturn(index+1,s1,mys);
    }
    if(strlen(s)==0) 
    { 
        mys[N-1]='\0';
        printf("%c%c,%c%c,%c%c,%c%c,%c%c\n",mys[0],mys[1],mys[2],mys[3],mys[4],
               mys[5],mys[6],mys[7],mys[8],mys[9]);
    }

} 
void main() 
{ 

    char  s[N]={'1','2','3','4','5','6','7','8','9','10'};
    char mys[N];
    strcpy(mys,s); 
    formturn(0,s,mys);
    return 0;
}

2008-11-05 23:00
gzbao9999
Rank: 1
等 级:新手上路
威 望:1
帖 子:40
专家分:0
注 册:2008-11-5
收藏
得分:0 
[bo][un]广陵绝唱[/un] 在 2008-11-5 23:00 的发言:[/bo]


/***********************************************************************

    依样画葫芦,写了这个程序,不过还只是知其然而不知其所以然,对于它的
原理,为什么会完成这样的功能,还是不明白。另外,这 ...


我看了下你的这段程序
这只是一个全排列的程序
而且 这段代码的 有很多多余和带有歧义的地方 我修改后如下
-------------------------------------------------
#include<stdio.h>
#include<string.h>
#define N 11
int time;
void formturn(int index,char *s,char *mys)
{
    char s1[N];
    char tmp;
    int i;
    for(i=0;i<strlen(s);i++)
    {
        tmp=s[i];
        mys[index]=s[i];
        s[i]='\0';
        strcpy(s1,s);
        
        strcat(s1,&s[i+1]);
        s[i]=tmp;
        formturn(index+1,s1,mys);
    }
    if(strlen(s)==0)
    {
    time++;
        mys[N-1]='\0';
        //printf("%c%c,%c%c,%c%c,%c%c,%c%c\n",mys[0],mys[1],mys[2],mys[3],mys[4],
              // mys[5],mys[6],mys[7],mys[8],mys[9]);
    }

}
void main()
{
    char  s[N]={'1','2','3','4','5','6','7','8','9','0'};
    printf("\n");
    char mys[N];
    //strcpy(mys,s);
    formturn(0,s,mys);
    printf("%d",time);
    return 0;
}

---------------------------------------
修正了的内容
1、main函数中 初始化 改为char  s[N]={'1','2','3','4','5','6','7','8','9','0'};
把你原来的10改为了0  因为作为char来讲 就只能存一位,即便你写的10 实际上也只是取了最后一位0
强烈建议你改用int型数组 因为 如果是要求排12个数或者更多的 你这个程序就洗白了

2、main函数中 注销掉了//strcpy(mys,s); 这一句,mys只是用来缓存结果用来打印的,这儿根本没有必要为其赋值
3、formturn函数中   s[i]=0; 更改为s[i]='\0';这儿的本意应该是插入一个结束符

下面把你这个递归函数讲解下
void formturn(int index,char *s,char *mys)
{
    char s1[N];
    char tmp;
    int i;
    for(i=0;i<strlen(s);i++)
    {
        tmp=s[i];           //记录本次循环所选中的值
        mys[index]=s[i];    //记录被当前递归层所取的值,是为了打印缓存的
        s[i]='\0';          //这儿是用来为下一句的拷贝做中止点用的
        strcpy(s1,s);       //拷贝'\0'之前的内容到数组s1中,而'\0'将会被下一句的拷贝内容所覆盖      
        strcat(s1,&s[i+1]); //拼接'\0'之后的内容到数组s1上(被'\0'所取代的内容是当前递归层所取的值)
                            //既然该值被当前层取了,下一层就不会有这个数可选了,此时的s1中为所有下一层可以
                            //取的数
        s[i]=tmp;           //还原本次循环所选中的值 因为下一次循环时 这个值就可以被下层选择
        formturn(index+1,s1,mys);  //递归
    }
     .....
}
---------------------------------------------
这个程序 如你所言 没有控制 两两一组中的大小顺序
每一组 可前大后小  也可前小后大 两者的几率是相同的  我们只考虑5组全为 前大后小 或者前小后大就行了

至于具体的实现 你看我在上面楼层写的程序吧 里面有讲实现原理

[[it] 本帖最后由 gzbao9999 于 2008-11-6 03:00 编辑 [/it]]
2008-11-06 02:49
广陵绝唱
Rank: 10Rank: 10Rank: 10
等 级:贵宾
威 望:29
帖 子:3607
专家分:1709
注 册:2008-2-15
收藏
得分:0 
回复 17# 的帖子
-------------

    谢谢这位热心的朋友。天快要亮了,脑袋痛得很,详细看了两遍,却想不出个所以然来。明天状态好的时候再研究,多谢。希望看了您的注释能令我明白这种程序。
2008-11-06 03:16
风居住的街道
Rank: 1
等 级:新手上路
帖 子:374
专家分:0
注 册:2008-10-24
收藏
得分:0 
14L的朋友:说的是分五组,这五组之间是没有顺序的,比如1,2,3,4分为两组,那么(1,2)(3,4)和(3,4)(1,2)是不是同一种分法呢?
而你算出的数字113400/5!刚好等于945,即我的结果,所以按照你的理解的话,你的程序的确是对的~~~~

下面是我的代码,其实也就只是一个全排列的代码改了一点点而已,嘿嘿~~~
程序代码:
#include <stdio.h>
#include <stdlib.h>

#define SWAP(a, b) {int t__=a; a=b; b=t__; }
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, len = 10, count = 0;

void select(int k)
{
    int i;
    if (k + 2 == len)
    {
        for (i = 0; i < len; i += 2)
            printf("(%d, %d)", a[i], a[i+1]);
        printf("\n");
        count++;
        return;
    }
    select(k + 2);
    for (i = k + 2; i < len; i++)
    {
        SWAP(a[k + 1], a[i]);
        select(k + 2);
        SWAP(a[k + 1], a[i]);
    }
}

int main(void)
{
    select(0);
    printf("count:%d\n", count);
    return 0;
}

2008-11-06 21:12
风居住的街道
Rank: 1
等 级:新手上路
帖 子:374
专家分:0
注 册:2008-10-24
收藏
得分:0 
to 广陵:
经过楼上那位朋友的修改,你的程序其实还是有冗余,我改了下:
程序代码:
#include <stdio.h>
#include <string.h>
#define N 10

int time = 0;

void formturn(int index, char *s, char *mys)
{
    int i;
    for (i = 0; i < N - index; i++)
    {
        char s1[N + 1];
        mys[index] = s[i];
        strncpy(s1, s, i);
        strcpy(s1 + i, s + i + 1);
        formturn(index + 1, s1, mys);
    }
    if (index == N)
        time++;
}

int main(int argc, char *argv[])
{
    int i;
    char s[N + 1], mys[N + 1];
    for (i = 0; i < N; i++) s[i] = '0' + i;
    formturn(0, s, mys);
    printf("%d\n", time);
    return 0;
}



不过,运行起来还是比我的稍慢一点儿,主要是字符串的复制花时间……

下面一个省去了临时的数组,不会更快(可能会慢,相比较strcpy和memmove的执行速度),但是内存会比较优。仅供参考(因为它实际上就是我上面贴的,我自己实现的代码……)
程序代码:
#include <stdio.h>
#include <string.h>
#define N 10

int time = 0;

void formturn(int index, char *s, char *ans)
{
    int i;
    for (i = 0; i < N - index; i++)
    {
        int slen = N - index - i + 1;
        ans[index] = s[i];
        memmove(s + i, s + i + 1, slen);
        formturn(index + 1, s, ans);
        memmove(s + i + 1, s + i, slen);
        s[i] = ans[index];
    }
    if (index == N)
    {
        /*
        for (i = 0; i< N; i++)
            printf("%c", ans[i]);
        printf("\n");
        // */
        time++;
    }
}

int main(int argc, char *argv[])
{
    int i;
    char s[N + 1], ans[N + 1];
    for (i = 0; i < N; i++) s[i] = '0' + i;
    formturn(0, s, ans);
    printf("%d\n", time);
    return 0;
}




[[it] 本帖最后由 风居住的街道 于 2008-11-6 23:30 编辑 [/it]]
2008-11-06 23:15
快速回复:求高手编写一个将十个数分成五组的程序!
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.034494 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved