| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 4093 人关注过本帖, 1 人收藏
标题:关于n的倍数,有没有高效的方法?
只看楼主 加入收藏
吹水佬
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:451
帖 子:10607
专家分:43186
注 册:2014-5-20
收藏
得分:0 
以下是引用九转星河在2016-12-23 14:34:05的发言:

嗯嗯,小意思,a=-a不是更直接么~直接在1和-1之间取~

是的,就是当一个开关。c[i]=1表示其代表的数被选中,为0则没选中,所有是1位置相对a数列的数的组合就是一组组合。
2016-12-23 15:17
吹水佬
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:451
帖 子:10607
专家分:43186
注 册:2014-5-20
收藏
得分:0 
主题用算组合的方法也可以。
这个是用“换位法”算组合。
示例:
/*

    从n个数中取出m个数的组合(换位法)

思路:
1、用一个数组c[n],数组元素的值为1表示其代表的数被选中,为0则没选中。
2、先将数组c[n]前m个元素初始化为1,表示第一个组合为前m个数。
3、之后从左到右扫描数组c[n],当找到第一个c[i]和c[i+1]元素值为“1和0”组合时,将其变为“0和1”组合(取反)。
   同时将其(c[i])左边的所有“1”全部移动到数组c[n]的最左端。
4、如果找不到“1 0”组合,即m个“1”全部移动到最右端时,就得到了最后一个组合。

例如求5中选3的组合:
1 1 1 0 0 //1,2,3
1 1 0 1 0 //1,2,4
1 0 1 1 0 //1,3,4
0 1 1 1 0 //2,3,4
1 1 0 0 1 //1,2,5
1 0 1 0 1 //1,3,5
0 1 1 0 1 //2,3,5
1 0 0 1 1 //1,4,5
0 1 0 1 1 //2,4,5
0 0 1 1 1 //3,4,5

*/

#include <stdio.h>
#include <stdlib.h>

int _factorial(n)   //阶乘
{
    int i, ret=1;
    for (i=2; i<=n; i++)
        ret *= i;
    return ret;
}

int _cnm(int n, int m)  //组合数
{
    //C(n,m) = n!/m!(n-m)! = C(n,n-m)
    return _factorial(n)/(_factorial(m)*_factorial(n-m));
}

void _print(int *a, char *c, int n) //打印一组
{
    int i;
    for (i=0; i<n; i++)
        if (c[i] == 1)
            printf("%d ", a[i]);
    printf("\n");
}

void _combine(int *a, int n, int m)
{
    int i, j, k;
        //用一个数组c[n],数组元素的值为1表示其代表的数被选中,为0则没选中。
    char *c=(char *)calloc(n, sizeof(char));

        //先将数组c[n]前m个元素初始化为1,表示第一个组合为前m个数。
    for (i=0; i<m; i++)
        c[i] = 1;
        
    while (1)
    {
            //打印一组
        _print(a, c, n);
        
            //之后从左到右扫描数组c[n],找到第一个c[i]和c[i+1]元素值为“1和0”组合。
        for (i=0; i<n-1; i++)
            if (c[i]==1 && c[i+1]==0)
                break;

            //如果找不到“1 0”组合,即m个“1”全部移动到最右端时,就得到了最后一个组合。
        if (i==n-1)
            break;

            //找到第一个c[i]和c[i+1]元素值为“1和0”组合时,将其变为“0和1”组合(取反)。
        c[i] = 0;
        c[i+1] = 1;

            // 同时将其(c[i])左边的所有“1”全部移动到数组c[n]的最左端。
        for (j=0; j<i && c[j]==1; j++) NULL;
        for (k=j,j++; j<i; j++)
            if (c[j] == 1)
            {
                c[k++] = 1;
                c[j] = 0;
            }
    }
    free(c);   
}

main()
{
    int a[]={1,2,3,4,5};
    int n=sizeof(a)/sizeof(int);
    int m;
    for (m=0; m<n; m++)
        printf("%d ", a[m]);
    m = 3;        
    printf("\nn = %d, m = %d\n", n, m);
    printf("C(n,m) = C(%d,%d) = %d\n", n, m, _cnm(5, m));
    _combine(a, n, m);
}

2016-12-23 15:46
搬砖
Rank: 2
等 级:论坛游民
帖 子:68
专家分:37
注 册:2016-10-13
收藏
得分:0 
回复 4楼 九转星河
嘻嘻,过不了样例哦,题目是要求最小的下标开始,无论构成的数的数量有多少
2016-12-23 16:26
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 13楼 搬砖
那就用吹版主的~那个感觉挺不错的~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2016-12-23 17:06
搬砖
Rank: 2
等 级:论坛游民
帖 子:68
专家分:37
注 册:2016-10-13
收藏
得分:0 
回复 12楼 吹水佬
我需要时间消化一下,感谢
2016-12-23 17:06
xzlxzlxzl
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:湖北
等 级:贵宾
威 望:125
帖 子:1091
专家分:5825
注 册:2014-5-3
收藏
得分:3 
回复 12楼 吹水佬
“不用递归,也不用多层循环嵌套,应该算是高效吧。”---吹版主这是使用障眼法,误导人哦!
看上去,主函数里就一层循环,可是循环里调用的函数里使用了好几处循环嵌套,算上主函数的那一层循环应该算是3层循环嵌套了!
不过,吹版主的组合算法值得学习(尽管完成题主题目不需要穷尽所有组合),我只会递归穷尽集合的所有组合,代码如下,请测试:
程序代码:
#include <stdio.h>

void fun(int a[],int b[],int m,int n,int l)
{
    int i,j,k,s;
    if(n>=l)return;
    for(i=0,s=0;b[i];i++)s+=b[i];
    b[i]=a[n];
    b[i+1]=0;
    s+=a[n];
    if(!(s%m))
    {
        for(j=0;j<i;j++)printf("%d+",b[j]);
        printf("%d=%d %d*%d\n",a[n],s,m,s/m);
    }
    for(i=n+1;i<l;i++)
    {
        fun(a,b,m,i,l);
        for(j=0;b[j];j++);
        b[j-1]=0;
    }
}

void main()
{
    int a[]={2,5,6,3,18,7,11,19},b[50],i,j;
    j=sizeof(a)/sizeof(int);
    for(i=0;i<j;i++)
    {
        b[0]=0;
        fun(a,b,8,i,j);
    }
}
2016-12-23 17:09
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
看来组合问题很有看头啊我当个小学生来学习一下~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2016-12-23 17:18
xzlxzlxzl
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:湖北
等 级:贵宾
威 望:125
帖 子:1091
专家分:5825
注 册:2014-5-3
收藏
得分:0 
回复 17楼 九转星河
听说做排列组合是进大公司必考的算法题!变态的phython已经一句就解决了.
好怕怕,幸好不是学这个专业,业余玩玩就行了,将来要靠这个吃饭估计我得饿死!
2016-12-23 17:23
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 16楼 xzlxzlxzl
那个……有点问题,如果数组a里有数字0的话会……

不过感觉我讲的有点多余因为题目要求N!=0~

[此贴子已经被作者于2016-12-23 17:26编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2016-12-23 17:25
xzlxzlxzl
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:湖北
等 级:贵宾
威 望:125
帖 子:1091
专家分:5825
注 册:2014-5-3
收藏
得分:0 
回复 19楼 九转星河
是的。如果集合里含有0,这个递归肯定不行。
可以在递归函数的参数里再加一个记录组合数量的参数,那样代码还少些。我平时处理字符串习惯了用标志位结束。
2016-12-23 17:29
快速回复:关于n的倍数,有没有高效的方法?
数据加载中...
 
   



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

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