前几天把金山公司给的程序题解了下,代码也贴出来了,原文在这里:http://student.csdn.net/space.php?uid=53444&do=blog&id=16634
编程 2
给定一个数组大小m和一个数组array
m = 10; array = {1,2,3,4,5,6,7,8,9,10}
求从array中任意取得n(n<=m)个数,使得和为m,总共有多少种取法,例如:10 1,9 2,3,5
方法原型 :int getotalNum (int[] array, int m);
原始代码优化的不是很到位,于是今天早上重写了下。
时间复杂度没有任何变化,仍然是 O(sigma(1<i<n,C(n,i))),只是新的算法剪枝效果比较好。
主要方法是把combine函数改写,把外部调用combine的循环移入combine函数内部,这样减少了combine函数中某些结果重复计算的冗余,从而改进了运行效率。
新代码如下
-
-
-
-
-
-
-
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define BUF_LEN 1024
-
- int compare ( const void *a , const void *b );
-
- int getotalNum (int array[], int m);
-
- void combine(int array[], int result[], int m);
-
- int main(void)
- {
- int buf[BUF_LEN], m, i;
-
- printf("Please input NO. of integer(s) no more than %d:", BUF_LEN);
- scanf("%d",&m);
- printf("Please input integer(s):");
- for(i=0; i<m; i++)
- {
- scanf("%d",buf+i);
- }
- printf("Totle %d way(s)/n", getotalNum(buf,m));
- return 0;
- }
-
- int compare ( const void *a , const void *b )
- {
- return *(int *)a - *(int *)b;
- }
-
- int getotalNum (int array[], int m)
- {
- int i, totle;
- int *result;
- qsort(array, m, sizeof(array[0]), compare);
-
- for(i=0; i<m; i++)
- {
- if (array[i] > m)
- {
- m = i;
- break;
- }
- }
- result = (int*)malloc(m * sizeof(int));
- if (result == NULL)
- return -1;
- combine(array, result, m);
- totle=*result;
- free(result);
- return totle;
- }
-
- void combine(int array[], int result[], int m)
- {
- int i,t;
- static int totle=0,level=0,begin=0,num=0;
-
- for (i=begin; i<=m; i++)
- {
- totle += array[i];
- result[level] = array[i];
- if ( totle < m)
- {
-
- if (level < m-1)
- {
- level++;
- t = begin;
- begin = i+1;
- combine(array, result, m);
- begin= t;
- level--;
- }
- }
- else if(totle > m)
- {
- totle -= array[i];
- break;
- }
- else
- {
- int j;
- for(j=0; j<=level; j++)
- printf("%d ",result[j]);
- puts("");
- num++;
- }
- totle -= array[i];
- }
-
- if (level == 0)
- {
- result[0] = num;
- }
- }
利用自己写的测试程序测试新旧两个程序getotleNum()所耗时间结果如下:
- E:/cbwork/testc/bin/Release>driver.exe
- generate_test_data_file ok!
- run tested programs
- data old(ms) new(ms)
- 50 75 2
- 60 289 5
- 70 998 15
- 80 3278 44
- 90 9409 107
- 100 26747 261
- 110 69330 601
gcc (GCC) 3.4.5 (mingw-vista special),O2开关优化,Win7, Intel 奔腾双核 1.8GHz,1G内存。
排除当时间较少时的噪音干扰,可以得到如下结论。
1、旧程序在数据量每增加10的时候时间增长为原来的约3倍
2、新程序在数据量每增加10的时候时间增长为原来的约2+倍
3、新程序比旧程序在同等数据量的情况下快约100倍。
同时给出测试驱动程序:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
-
- #define PROGRAM_NAME_TYPE "xxx.exe"
- #define IN_PIPE "<"
-
- void generate_test_data_file(int from, int to, int step);
- void run_programs(int from, int to, int step);
- int main()
- {
- int from=50,to=110,step=10;
- printf("generate_test_data_file ");
- generate_test_data_file(from,to,step);
- puts("ok!");
- puts("run tested programs");
- puts("data/t/told(ms)/t/tnew(ms)");
- run_programs(from,to,step);
- return 0;
- }
- void run_programs(int from, int to, int step)
- {
- char cmd[FILENAME_MAX];
- int len;
- for(;from<=to;from+=step)
- {
- len=strlen(PROGRAM_NAME_TYPE)+strlen(IN_PIPE);
- itoa(from,cmd+len,10);
- printf(cmd+len);
- printf("/t/t");
- memcpy(cmd,"old.exe<",strlen("old.exe<"));
- system(cmd);
- printf("/t/t");
- memcpy(cmd,"new.exe<",strlen("new.exe<"));
- system(cmd);
- puts("");
- }
- }
- void generate_test_data_file(int from, int to, int step)
- {
- FILE * fp;
- int i;
- char filename[FILENAME_MAX];
- for(;from<=to;from+=step)
- {
- fp=fopen(itoa(from,filename,10),"w");
- if(fp==NULL)
- {
- puts("generate test data file error!");
- exit(1);
- }
- fprintf(fp,"%d/n",from);
- for(i=0;i<from;i++)
- {
- fprintf(fp,"%d ",i);
- }
- fclose(fp);
- }
-
- }
统计系统