以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 算法理论与分析 』  (http://bbs.xml.org.cn/list.asp?boardid=60)
----  一个很难的数学算法大家进来帮帮小妹啊很急  (http://bbs.xml.org.cn/dispbbs.asp?boardid=60&rootid=&id=23227)


--  作者:waterzhouliu
--  发布时间:10/18/2005 9:48:00 AM

--  一个很难的数学算法大家进来帮帮小妹啊很急
set 20>m>=n>0,
exp:
input m=8,
input n=4.

有多少组4个数加起来等于8的
5个
1115, 1241,2222,3212,3311

很急呀
大家帮帮忙


--  作者:binaryluo
--  发布时间:10/18/2005 11:58:00 AM

--  
感觉有点类似24点。
--  作者:waterzhouliu
--  发布时间:10/18/2005 12:01:00 PM

--  
帮帮小妹有人能写出来吗
--  作者:binaryluo
--  发布时间:10/18/2005 12:04:00 PM

--  
24点你可以参考下这里:
http://www.ieee.org.cn/dispbbs.asp?boardID=60&ID=15720
--  作者:waterzhouliu
--  发布时间:10/18/2005 12:07:00 PM

--  
但是M N都是动态的,是用户自己输入的呀
--  作者:binaryluo
--  发布时间:10/18/2005 12:11:00 PM

--  
那篇文章里的算法是根据24点扩展出来了一个算法,他里面的牌数和点数也是动态的。
--  作者:waterzhouliu
--  发布时间:10/18/2005 12:30:00 PM

--  
不是的哦,看不明白

--  作者:waterzhouliu
--  发布时间:10/18/2005 12:35:00 PM

--  
谁能把具体的算法给我么?
--  作者:binaryluo
--  发布时间:10/19/2005 11:33:00 AM

--  
帮你想下。。。
--  作者:galois
--  发布时间:10/22/2005 6:11:00 PM

--  
应该是很简单的组合算法吧
--  作者:galois
--  发布时间:10/22/2005 6:13:00 PM

--  
相当于:8个不编号的球放入4个不编号的盒子,有几种放法咯。

用动态规划可以解吧。就不知道最好的解法是什么。


--  作者:xxzzxx
--  发布时间:10/26/2005 6:10:00 PM

--  
import java.util.*

class Combines
{
    Vector allCombines = new Vector();
    int[] oneCombine;
    
    public static void main(String[] args)
    {
        int n=4, m=8;
        Combines c = new Combines();
        
        int [][] result = c.getAllCombines(n, m);
        
        for (int i=0; i<result.length; ++i)
        {
            for (int j=0; j<n; ++j)
            {
               System.out.print(result[i][j]+" ");    
            }
            System.out.println();    
            
        }
    }
    
    
    public int[][]  getAllCombines(int n, int m)
    {
        int [][] result;
        
        oneCombine = new int [n];
        
        getOneCombine(0, n, m);
        
        result = new int [allCombines.size()][n];
        
        for (int i=0; i<allCombines.size(); ++i)
        {
            ArrayList item = (ArrayList)allCombines.get(i);
            for (int j=0; j<n; ++j)
            {
                result[i][j] = ((Integer)item.get(j)).intValue();
            }
        }
        
        return result;
    }
    
    boolean isCurCombineCorrect(int m)
    {
        int sum = 0;
        
        for (int i=0; i<oneCombine.length; ++i)
        {
            sum += oneCombine[i];
        }
        
        if (sum == m)
        {
            return true;
        }
        
        return false;
    }
    
    boolean isArraylogicalEqual(ArrayList aItem, ArrayList bItem)
    {
        int length = aItem.size();
        int i=0, j=0;
        
        for (i=0; i<length; ++i)
        {
            boolean equal = false;
            int aVal = ((Integer)aItem.get(i)).intValue();
            
            for (j=0; j<length; ++j)
            {
                if ( aVal == ((Integer)bItem.get(j)).intValue() )
                {
                    equal = true;
                }
            }
            
            if (equal == false)
            {
                return false;
            }
        }
        
        for (i=0; i<length; ++i)
        {
            boolean equal = false;
            int aVal = ((Integer)bItem.get(i)).intValue();
            
            for (j=0; j<length; ++j)
            {
                if ( aVal == ((Integer)aItem.get(j)).intValue() )
                {
                    equal = true;
                }
            }
            
            if (equal == false)
            {
                return false;
            }
        }
        
        return true;
    }
    
    boolean isCurCombineExist()
    {
        ArrayList curItem = new ArrayList();
        
        
        for (int k=0; k<oneCombine.length; ++k)
        {
             curItem.add(new Integer(oneCombine[k])) ;
        }
        
        
        for (int i=0; i<allCombines.size(); ++i)
        {
            ArrayList aItem = (ArrayList)allCombines.get(i);
            
            if (isArraylogicalEqual(aItem, curItem))
            {
                return true;
            }
        }
        
        return false;
    }
    
    void getOneCombine(int index, int n, int m)
    {
        if (index >= n)
        {
            //got one!
            if (isCurCombineCorrect(m))
            {
                if (isCurCombineExist() == false)
                {
                    ArrayList item = new ArrayList();
                    
                    for (int k=0; k<oneCombine.length; ++k)
                    {
                        item.add(new Integer(oneCombine[k]));
                    }
                    
                    allCombines.addElement(item);
                }
            }
            
            return;
        }
        
        //for (int i=0; i<n; ++i)
        {
            for (int j=1; j<=m-n+1; ++j)
            {
                oneCombine[index] = j;
                getOneCombine(index+1, n, m);
            }
        }
    }
    
}


--  作者:xzjxu
--  发布时间:10/27/2005 2:20:00 PM

--  
楼上,不用那么复杂吧!
我给一个VB写的程序:
Private Sub Command1_Click()
    Dim a() As String, k As Integer
    Dim m As Integer, n As Integer
    m = Val(Text1)
    n = Val(Text2)
    k = com(m, n, a)
    Text3 = k
    For i = 1 To k
        List1.AddItem a(i)
    Next i
End Sub

Private Function com(m As Integer, n As Integer, a() As String) As Integer
    Dim b() As String, k As Integer, k1 As Integer, s As Integer
    Dim idx As Integer
    ReDim a(0)
    If m = n Then
        ReDim a(1)
        For i = 1 To n - 1
            a(1) = a(1) & "1 "
        Next i
        a(1) = a(1) & "1"
        com = 1
    ElseIf n = 1 Then
        ReDim a(1)
        a(1) = CStr(m)
        com = 1
    Else
        For i = 1 To m - n + 1
            k = com(m - i, n - 1, b)
            u = UBound(b)
            For j = 1 To u
                k1 = InStr(b(j), " ")
                If k1 = 0 Then
                    s = Val(b(j))
                Else
                    s = Val(Mid(b(j), 1, k1 - 1))
                End If
                If i >= s Then
                    idx = idx + 1
                    ReDim Preserve a(idx)
                    a(idx) = CStr(i) & " " & b(j)
                End If
            Next j
        Next i
        com = UBound(a)
    End If
End Function


实在没有找到更好的论坛,还是凑合来这里吧


--  作者:snail
--  发布时间:11/18/2005 10:00:00 AM

--  
不晓得楼主要的是不这样,最笨的算法更好的还在想之中.
main()
{
  int i,j,k,l,sum,id;
  id=0;
  for(i=1;i<8;i++)
    {  sum=0;
       for(j=0;j<8;j++)
        for(k=0;k<8;k++)
           for(l=0;l<8;l++)
              {
                sum=i+j+k+l;
                if(sum==8)    
                  id+=1;
               }
    }
   id=id+1;
   printf("the number is:%d",id);
}
--  作者:enorm
--  发布时间:12/1/2005 8:53:00 PM

--  
/*by  enorm*/
#include "stdio.h"
int cont [21];
void cal(int m,int n,int num)
{
 

   if(m>20||n>20||n<=0||m<=0)
   {

     return;
   }
   if(m<n)
   {
    return;
   }
   for(int i=1;i<=m-n+1;i++)
   {  
    cont[n-1]=i;
    cal(m-i,n-1,num);
   }
   if(n==1)
   {
      for(int u=0;u<num;u++)
     printf("%d ",cont[u]);
   printf("\n");
  }

}
void cal(int m,int n)
{
 cal(m,n,n);
}
void main()
{
  cal(15,5);

}

c语言精炼,呵呵

[此贴子已经被作者于2005-12-1 22:13:42编辑过]

--  作者:dolphin_lzy
--  发布时间:1/8/2006 1:30:00 PM

--  
能把规则在详细的说明一下吗?比如产生的只能是1-9数字吗?算法实现好象不是很难啊?可能效率很重要了吧?

--  作者:wcdxyl
--  发布时间:3/22/2006 4:04:00 PM

--  
package ieee;

public class Composite {

 public void getComposite(int a, int b) {

  int n = 0;
  int y = 0;

  for (double i = Math.pow(10, b - 1); i < Math.pow(10, b) - 1; i++) {
   // 每个数
   String itos = String.valueOf((int) i);

   for (int j = 0; j < itos.length(); j++) {
    // 每个数字
    String temp = itos.substring(j, j+1);
    y = y + Integer.parseInt(temp);
   }
   if (y == a)
    n++;
   y = 0;
  }
  System.out.println(n);
 }

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  new Composite().getComposite(8, 4);
 }

}


--  作者:bj15828
--  发布时间:3/26/2006 11:27:00 PM

--  
我大概写些思想和伪代码:
设m=8 ,n=4.按要求说我们可以理解为一个n层的树,只要树遍历到了,那么解也就出来了.那么树是怎么构造呢?
首先来看究竟m,n和树的层中元素有什么关系?m=8,n=4,也就是说位于第一层的元素必然满足这么一个关系:m-n+1,也就是说第一层最多可为5个元素,分别是5,4,3,2,1,第二层的构造是按照第一层中每个元素分别来构造,对于元素1来说,它的第二层元素为1,2,3,4,5;元素2为1,2,3,4.满足下面的关系式:
  单个元素的下一层对应的元素个数 = m-当前层数-n+当前总值  当前总值=遍历经过的元素值之和

有了上面的公式,用栈来实现遍历.

/*

while((m-n+1)>0)
 {
  Node.value = m-n+1;
  Node.floor = 1;
  Stack.push(Node);
  (m-n+1)--;
 }
while(棧不为空){//构造下一层的元素,并放入棧中
 tmpNode = stack.pop();
 curfloor = tmpNode.floor+1;
 curValue = curValue +tmpNode.value;
 tmpTrace[curfloor -1 ] =curValue;
 while(m-curValue-n+curfloor > 0 && curfloor <n)
 {
  int i = m-curValue-n+curfloor ;
  Node.value = i;
  Node.floor = curfloor;
  stack.push(Node);
  (m-curValue-n+curfloor) --;
 }
 curfloor = tmpNode.floor;
 if (curfloor = n-1)
 {
  tmpTrace[curfloor+1]= m-curValue;
  if (compare(tmpTrace,Trace))//如果路径没有被遍历过,则放入到Trace中
  {
   把tmpTrace放入Trace中;//Trace用来保存遍历到的路径
  }
 }
 curValue = curValue - tmpNode.value;//把curValue恢复到没有修改以前,以便下个元素遍历
}
*/



--  作者:cll121
--  发布时间:3/29/2006 10:35:00 AM

--  
真深奥啊我看不懂啊
--  作者:dhxu757
--  发布时间:4/18/2006 9:58:00 PM

--  
#include <math.h>
#include <conio.h>

int main(])
{
 unsigned long it, minit, maxit;
 int n, m;
 int s;
 int r;
 int count = 0;

 scanf("%d, %d", &n, &m);

 maxit = (unsigned long)pow(10.0, n);
 minit = (unsigned long)pow(10.0, n-1);

 for ( it = minit; it < maxit; it++ )
 {
  r = it;
  s = 0;
  while(r>0)
  {
   s = s + (r % 10);
   r = r / 10;
  }
 
  if ( s == m )
  {
   printf("%8ld", it);
   count++;
  }
 }

 printf("\nCount = %d", count);

 getch();

 return 0;
}


--  作者:dhxu757
--  发布时间:4/18/2006 10:03:00 PM

--  
一个很简单的问题, 可以不要涉及到高深的算法即可求解.我的程序在楼上.请大家指正.
--  作者:yibical
--  发布时间:4/29/2006 10:44:00 AM

--  
算法我想出来了,可以和我联系QQ:401350842
--  作者:tomlillite
--  发布时间:5/9/2006 10:56:00 AM

--  
#include<iostream.h>
void main()
{int n;
cout<<"请输入要分解的数据:"<<endl;
cin>>n;
int a,b,c,d;
for(a=1;a<n;a++)
{for(b=a;b<n;b++)
{for(c=b;c<n;c++)
{for(d=c;d<n;d++)
   {if(a+b+c+d==n&&a<=b&&b<=c&&c<=d)
       cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
   }
}
}
}
}
--  作者:wanghuicn2008
--  发布时间:7/1/2006 4:58:00 PM

--  
组合数学中的母函数可解这个问题,具体看《组合数学及算法》中科大出的

--  作者:binaryluo
--  发布时间:7/2/2006 11:23:00 AM

--  
看了大家写的程序实现,作了个总结。

解决方法大致可以分为以下两种思路:
1.简单的循环测试。这种方法的时间复杂度是O(m^n),注:m^n表示m的n次方。这种方法的代表是:14楼,15楼,23楼。其中,15楼采用递归实现,但在时间复杂度上跟用非递归实现是一样的。

2.将结果的数串以一个整体(大整数)考虑,先设置好循环的范围,然后再在该范围内测试这些大整数的各个数位取出来相加,看结果是否是正确解。例如m=8,n=4,意思是找出4个数字相加的结果是8的全部组合。用方法2的思想,他的处理思路是,4个数字如果组成一个大整数的话,范围是1000-9999之间,即10^3到10^4之间,所以原题可以考虑成在1000-9999之间找出各个数位加起来是8的全部数字。取各个数位的时候采用了模10的方法。
这种方法只有一个循环,但是该循环的范围比较大,而且中间在取各个数位的时候也有一个常数阶的循环,这种方法的时间复杂可表示为O(n*(10^n - 10^(n-1)))。这种方法的代表是:17楼,20楼。前者是java版的,后者是C语言版的。

可以证明两算法的时间复杂度满足如下关系:
当m<=10时,m^n < n*(10^n - 10^(n-1));
当m > 10时,m^n > n*(10^n - 10^(n-1))。

在分析过程中略去了有些朋友的解法,在此表示歉意。另外,由于个人水品有限,在分析过程中如果有错误的地方还望大家指正。


--  作者:richardxx
--  发布时间:8/24/2006 11:11:00 AM

--  
#include <stdio.h>

int f(int m,int n)
{
 int i;
 int s=0;
 int stop;
 if (m==n)
  return 1;
 stop=m-n>n?n:m-n;
 for (i=1;i<=stop;++i)
  s+=f(m-n,i);
 return s;
}

int main()
{
 int m,n,result;
 scanf("%d %d",&m,&n);
 result=f(m,n);
 printf("\nThe answer is:%d\n",result);
 return 0;
}


--  作者:richardxx
--  发布时间:8/24/2006 11:15:00 AM

--  
以上的程序直接利用关系式:

f(m,n)=sum{[i=1 to min(m-n,n)] f(m-n,i)}
这种题数学方法是最简单的。


--  作者:dvdface
--  发布时间:10/24/2008 5:16:00 PM

--  
这不就是枚举么? 为什么难啊?

还可以用减枝法来减少计算量.


--  作者:richardxx
--  发布时间:10/24/2008 5:22:00 PM

--  
以下是引用dvdface在2008-10-24 17:16:00的发言:
这不就是枚举么? 为什么难啊?

还可以用减枝法来减少计算量.


汗,枚举,人家要的是DP解。。。


--  作者:dvdface
--  发布时间:10/24/2008 6:42:00 PM

--  
有道理, 用DP可以更加减少计算量. 就是实现麻烦点.

要存储 子问题的 解.

不错


--  作者:kid1986
--  发布时间:10/25/2008 2:05:00 PM

--  
#include <stdio.h>
main()
{
 int i,j,k,l,sum,id;
  id=0;
  for(i=1;i<8;i++)
    {  sum=8;
       for(j=1;j<8;j++)
        for(k=1;k<8;k++)//外层循环没什么好解释的就一个算吧
  {
   l=sum-i-j-k;//最后一层循环没必要了改成直接看l是否存在就可以减少了时间复杂度,不知道能接受不
   if(l>0)
   {
    id=id+1;
    printf("%d+%d+%d+%d=%d\n%d\n",i,j,k,l,sum,id);
   }
   continue;
  }
    }
   
}
14楼友的改版
--  作者:hust512
--  发布时间:2/26/2009 11:40:00 PM

--  
哈哈,很早的贴嘛!
不久两层for循环就解决了吗!
当局者迷呀!
--  作者:computernewuser44
--  发布时间:3/11/2009 11:29:00 PM

--  
这是组合数学中的“拆分数”,必须用生成函数。
∑(上限:∞)(下限:n=0)pn(下标:n)Xn(n次方)=∏(上限:∞)(下限:k=0)(1-Xk(k次方))-1(-1次方);
用级数展开Xn(n次方)系数pn为拆分数。

由于有文字不好写“n次方”“累加,累乘”原谅。
可见<<组合数学第三版>>Brualdi,144页,188页。
如果按14楼写法,n的拆分数有写:n=a1*n+a2*(n-1)......an*1;n次for,复杂度O(n,n次方)


--  作者:computernewuser44
--  发布时间:3/11/2009 11:32:00 PM

--  
具体实现见《组合数学的算法与程序设计》好像是作者吴文虎。
--  作者:ZaakDov
--  发布时间:6/5/2009 6:28:00 PM

--  
dp[n,m]=dp[n-1][m-1]+dp[n-m][m]

dp[n][n]=1;

如此DP

时间O(n*n)


--  作者:fairywell
--  发布时间:3/10/2010 11:15:00 AM

--  
粗看,我觉得笨方法可以用暴力+pruning,聪明点可以从8的整数分解开始反过来解决
--  作者:jsjkxlt99
--  发布时间:4/13/2010 1:02:00 AM

--  log

假设语言选取是自由的。

由于 8 <= 20. 所以要求均为正数时就是4-1=3个1,8-4=4个0的全组合。用prolog 很容易生成。

(一般x1+x2+x3+ ...+ xn = r, 要求xi >=0时就是组合数C(n+r-1,r))

在有上界限制时,比如 m >= xi >=0,而m < r,则可以用mathematica和生成多项式,
(1+x1+x1^2+...+x1^m)(1+x2+...)...(1+xn+...), 最后截取所有指数和为r的项且不计变元的不同即可。



--  作者:蹩脚的黑客
--  发布时间:10/7/2010 10:49:00 PM

--  
int main(int argc, char* argv[])
{
 int i,j,k,l;
 int m;
 for(i=1;i<20;i++)
  for(j=19;j>=i;j--)
   for(k=19;k>=i&&k>=j;k--)
    for(l=19;l>=i&&l>=j&&l>=k;l--)
    {m=i+j+k+l;
     if(m==8) printf("%d %d %d %d\n",i,j,k,l);
     continue;
    }

}


--  作者:huiru
--  发布时间:10/18/2010 2:32:00 PM

--  fsd
不是很清楚哈,也许是太难了,再继续找找看,看有没有别的什么答案没哦。
[url=http://www.eluxurys-store.com/prada.html]prada[/url]
W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
281.250ms