當前位置:商標查詢大全網 - 彩票查詢 - 壹個計算的程序問題

壹個計算的程序問題

看了下妳的題目覺得有意思,就寫了個,功能被我擴展了壹點,不過寫的有點糟糕,其實還有N多不完善的地方,比如存結果的數組大小要在編譯期間確定,使用鏈表或者動態調整數組的話也沒什麽難的,不過確憑空增加了代碼的復雜度,還有查找所有滿足時使用的是遞歸並且那個函數參數有點多所以範圍大壹點可能導致棧溢出,所以暫時寫成這樣了,有什麽不懂的話可以發消息給我:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <assert.h>

int Prepare(int sum, int n)

{

--n;

int i = n * (1 + n) / 2;

return sum - i;

}

int NoDummy(int* beg, int* end, int dummy)

{

while(beg != end)

if(*beg++ == dummy)

return 0;

return 1;

}

int NoDupNum(int* beg, int* end)

{

int* p;

for(; beg != end; ++beg)

for(p = beg + 1; p != end; ++p)

if(*p == *beg)

return 0;

return 1;

}

int NoDupSeq(int** beg, int** end, int* p, int n)

{

while(*beg && (beg != end))

{

if(memcmp(*beg, p, sizeof(int) * n) == 0)

return 0;

++beg;

}

return 1;

}

inline int Cmp(const void* lhs, const void* rhs)

{

return *(const int*)rhs - *(const int*)lhs;

}

void FindAllMatch(int sum, int baseNum, int nextNum, int cn, int n, int* pn, int* beg, int* end, int** outBeg, int** outEnd, int dummy)

{

int i, *tmp, **nullPos;

for(i = nextNum; i >= baseNum; --i)

{

if(*pn > n)

{

for(tmp = end - (*pn - n); tmp != end; ++tmp)

*tmp = dummy;

}

*pn = n;

*(end - n) = i;

if(sum - i == 0 && NoDummy(beg, end, dummy) && NoDupNum(beg, end))

{

tmp = (int*)malloc(sizeof(int) * cn);

memcpy(tmp, beg, sizeof(int) * cn);

qsort(tmp, cn, sizeof(int), Cmp);

if(NoDupSeq(outBeg, outEnd, tmp, cn))

{

nullPos = outBeg;

while(*nullPos && nullPos != outEnd)

++nullPos;

if(nullPos == outEnd)

{

puts("Number of results bigger than the size of result array.");

exit(1);

}

*nullPos = tmp;

}

else

free(tmp);

}

if(sum - i > 0 && n - 1 > 0)

FindAllMatch(sum - i, baseNum, sum - i, cn, n - 1, pn, beg, end, outBeg, outEnd, dummy);

}

}

void GetResult(int lb, int ub, int n, int goal, int** resBeg, int** resEnd)

{

assert(lb < ub);

int* tmp = (int*)malloc(sizeof(int) * n);

int dummy = ub + 1;

int nextNum = goal < ub ? Prepare(goal, n) : ub;

int fn = n;

FindAllMatch(goal, lb, nextNum, n, n, &fn, tmp, tmp + n, resBeg, resEnd, dummy);

free(tmp);

}

int Contains(int* beg, int* end, int* subBeg, int* subEnd)

{

int* p;

for(; subBeg != subEnd; ++subBeg)

{

for(p = beg; p != end; ++p)

{

if(*p == *subBeg)

break;

}

if(p == end)

return 0;

}

return 1;

}

void SearchForSuit(int n, int** resBeg, int** resEnd, int* beg, int* end, FILE* output)

{

int** p, *x;

for(p = resBeg; *p && p != resEnd; ++p)

{

if(Contains(*p, *p + n, beg, end))

{

for(x = *p; x != *p + n; ++x)

fprintf(output, "%d ", *x);

putc('\n', output);

}

}

}

void CleanUpMemory(int** resBeg, int** resEnd)

{

int** p = resBeg;

while(*p && p != resEnd)

free(*p++);

}

#define RES_ARRAY_SIZE 500 // 結果數組大小,不夠的話自己調大點

int main()

{

int goal = 23; // 數字和

int n = 6; // 由6個數字相加得

int lb = 1, ub = 33; // 範圍

int a[] = {4, 3}; // 其中包含4, 3

// 存所有滿足條件的結果

int *resBeg[RES_ARRAY_SIZE] = {0};

int ** resEnd = resBeg + RES_ARRAY_SIZE;

// 範圍1~33, 6個數字的和為23, 結果存在resBeg數組裏

GetResult(lb, ub, n, goal, resBeg, resEnd);

// 篩選出有4, 3兩個數的序列,打印到stdout, 妳可以把它改成壹個文件指針

SearchForSuit(n, resBeg, resEnd, a, a + sizeof(a) / sizeof(a[0]), stdout);

// 整理內存

CleanUpMemory(resBeg, resEnd);

return 0;

}

方法二:

用今天自己找出的求組合的方法,優化壹下,效率有所提高(排除了去重等過程):

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

void Print(int* beg, int* end)

{

while(beg != end)

printf("%d ", *beg++);

putchar('\n');

}

inline int Prepare(int goal, int n)

{

return goal - (n - 1) * n / 2;

}

typedef unsigned long long ull;

// count for combinations

ull CC(ull n, ull r)

{

ull Anr = 1;

ull Arr = 1;

for(; r > 0; Anr *= n--, Arr *= r--);

return Anr / Arr;

}

int Sum(int* beg, int* end)

{

int sum = 0;

while(beg != end)

sum += *beg++;

return sum;

}

// 求組合序列的函數

int** C(int n, int m, int** resBeg, int** resEnd, int goal)

{

int i;

int *p, *x, *trace_back, **nullPos;

p = (int*)malloc(sizeof(int) * m);

for(i = 1; i <= m; ++i)

p[i - 1] = i;

trace_back = p + m - 1;

if(m != n)

do{

if(Sum(p, p + m) == goal)

memcpy(*resBeg++, p, sizeof(int) * m);

if(*trace_back < n)

++*trace_back;

else

{

while(*trace_back - *(trace_back - 1) <= 1)

--trace_back;

--trace_back;

++*trace_back;

for(x = trace_back + 1; x != p + m; ++x)

*x = *(x - 1) + 1;

trace_back = p + m - 1;

}

}while(*p != n - m + 1);

if(Sum(p, p + m) == goal)

memcpy(*resBeg++, p, sizeof(int) * m);

nullPos = resBeg;

while(nullPos != resEnd)

{

free(*nullPos);

*nullPos++ = 0;

}

free(p);

return resBeg;

}

int Contains(int* beg, int* end, int* subBeg, int* subEnd)

{

int* p;

if(subEnd - subBeg > end - beg)

{

puts("Range error!");

return 0;

}

for(; subBeg != subEnd; ++subBeg)

{

for(p = beg; p != end; ++p)

if(*subBeg == *p)

break;

if(p == end)

return 0;

}

return 1;

}

void SearchForSuit(int goal, int n, int* beg, int* end)

{

int m = Prepare(goal, n);

int** res, **resEnd, **p;

ull cc;

if(m < n)

{

puts("No solution!");

return;

}

cc = CC(m, n);

res = (int**)malloc(sizeof(int*) * cc);

for(p = res; p != res + cc; ++p)

*p = (int*)malloc(sizeof(int) * n);

resEnd = C(m, n, res, res + cc, goal);

if(resEnd == res)

puts("No solution!");

else

{

for(p = res; p != resEnd; ++p)

if(Contains(*p, *p + n, beg, end))

Print(*p, *p + n);

for(p = res; p != resEnd; ++p)

free(*p);

}

free(res);

}

int main()

{

int elems[] = {2, 3};

SearchForSuit(23, 6, elems, elems + 2);

return 0;

}

PS: 不知道我這些方法叫不叫"全真模擬選號"...