微剋多資訊

 找回密碼
 註冊

Login

Login

搜索
回覆 9則 瀏覽 1782篇

幾A幾B

該用戶從未簽到

發表於 2012-11-26 18:44 | 顯示全部樓層 |閱讀模式
本帖最後由 chiayinwang 於 2012-11-26 18:47 編輯

全部的函數都是自己寫的
如有疑問 歡迎討論哦!!!
轉載請註明出處
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4. //Copyright Chiayin Wang All Right Reserved
  5. //幾A幾B
  6. void setHidden(int ans[]){
  7.   int w=10;
  8.   for(int i=0;i<4;i++){
  9.     ans=rand()%9;
  10.     if(w==ans){
  11.       i--;
  12.     }
  13.     w=ans;
  14.   }
  15.   if((ans[1]==ans[3])||(ans[0]==ans[2])||(ans[0]==ans[3])){setHidden(ans);};
  16.   //printf("Ans is:%d%d%d%d\n",ans[0],ans[1],ans[2],ans[3]);//測試用(可觀察亂數產生結果)
  17. }
  18. void guessNumber(int ip[]){
  19.   int w=10,n,k,t;
  20.   scanf("%d",&n);
  21.   k=n;
  22.   for(int i=3;i>-1;i--){
  23.     ip=k%10;
  24.     k=k/10;
  25.   }
  26.   k=5,t=0;
  27.   for(int j=0;j<4;j++){
  28.     k--;t++;
  29.     for(int i=0;i<k;i++){
  30.       w=ip;
  31.       if(w==ip[i+(t)]){
  32.         guessNumber(ip);
  33.       }
  34.     }
  35.   }
  36. }
  37. int checkA(int ip[],int ans[]){
  38.   int result=0;
  39.   for(int i=0;i<4;i++){
  40.     if(ip==ans){
  41.       result++;
  42.     }
  43.   }
  44.   return result;
  45. }
  46. int checkB(int ip[],int ans[]){
  47.   int result=0;
  48.   for(int i=0;i<3;i++)
  49.   {
  50.     if(ans==ip[i+1]){result++;}
  51.     if(ip==ans[i+1]){result++;}
  52.   }
  53.   for(int i=0;i<2;i++)
  54.   {
  55.     if(ans==ip[i+2]){result++;}
  56.     if(ip==ans[i+2]){result++;}
  57.   }
  58.   if(ans[0]==ip[3]){result++;}
  59.   if(ip[0]==ans[3]){result++;}
  60.   return result;
  61. }
  62. int main(){
  63.   int ans[4],ip[4],a=0,b;
  64.   srand((unsigned int)time(NULL));
  65.   setHidden(ans);
  66.   while(a!=4)
  67.   {
  68.     printf("請猜四位數不重複的數字: \n");
  69.     guessNumber(ip);
  70.     a=checkA(ip,ans);
  71.     b=checkB(ip,ans);
  72.     printf("%dA%dB\n",a,b);
  73.   }
  74.   printf("恭喜答對囉! \n");
  75.   system("pause");
  76.   return 0;
  77. }
複製代碼

該用戶從未簽到

發表於 2012-11-27 04:00 | 顯示全部樓層
不好聽的就不說了,但  setHidden 很明顯是個敗筆。
回覆

使用道具 舉報

該用戶從未簽到

 樓主| 發表於 2012-11-27 13:20 | 顯示全部樓層
edisonx 發表於 2012-11-27 04:00
不好聽的就不說了,但  setHidden 很明顯是個敗筆。

有許多地方是可以用比較快速的方法寫
但是這個程式我是要照題目格式寫 所以有些格式沒辦法改
回覆

使用道具 舉報

該用戶從未簽到

發表於 2012-11-27 13:41 | 顯示全部樓層
本帖最後由 ad6543210 於 2012-11-27 13:43 編輯
chiayinwang 發表於 2012-11-27 13:20
有許多地方是可以用比較快速的方法寫
但是這個程式我是要照題目格式寫 所以有些格式沒辦法改 ...

setHidden的問題
1. 看起來你是想用遞迴來解決數字重複問題,但是你的輸入變數名稱也叫做ans,而且沒有任何判斷是否有輸入
2. w=10不知道有何作用
3. 可以參考一下,這種寫法也比較常見,也許搜尋一下就會有一樣的
最後ans就是你要的,而且每次都不同 (因為有srand)
  1. int i,j;
  2. srand(time(0));
  3. for(i=0; i<4; i++) {
  4.     ans[i] = rand()%10;
  5.     for(j=0; j<i; j++){
  6.         while(ans[i] == ans[j]) { // 使第2個不會跟第1個重複,第3個不會跟第1/2個重複...以此類推
  7.             ans[i] = rand()%10;
  8.         }
  9.     }
  10. }
複製代碼
PS.C語言跟JAVA是學資料結構的好東西 ~~
PS2.上面的ans如果改用全域變數+指針會更讚 EX: *(ans + i) = rand()%10;
回覆

使用道具 舉報

該用戶從未簽到

 樓主| 發表於 2012-11-27 13:52 | 顯示全部樓層
ad6543210 發表於 2012-11-27 13:41
setHidden的問題
1. 看起來你是想用遞迴來解決數字重複問題,但是你的輸入變數名稱也叫做ans,而且沒有任 ...

感謝你的建議
整體來說就是換用for+while雙重迴圈來逐一檢查 對吧!?
回覆

使用道具 舉報

該用戶從未簽到

發表於 2012-11-27 14:18 | 顯示全部樓層
chiayinwang 發表於 2012-11-27 13:52
感謝你的建議
整體來說就是換用for+while雙重迴圈來逐一檢查 對吧!?

是的

如果你學到指針了
那麼建議用指針
(指針好用,但是第一次看的人可能會看不懂,呵呵)
回覆

使用道具 舉報

該用戶從未簽到

發表於 2012-11-27 17:43 | 顯示全部樓層
本帖最後由 edisonx 於 2012-11-27 17:52 編輯

來個有建設性的發言好了。

setHidden 是遞迴,但「有機率」會產生 stack overflow 造成程式錯誤。今天換個偏激一點的問題:從 1~100000 產生 99998 個不重覆亂數怎麼跑?拿原本的寫法很容易寫到掛 (stack overflow)。


我們重新定義這個問題

整數從 A 到 B (含 A 含 B),範圍是 RANGE ( RANGE = B-A+1) ,如何產生 N (N<=RANGE) 個不重覆亂數?

ad6543210 給了一份 solution ,在針對 ( N / RANGE  ) 比值較小的時候,用該法是首選,若 N / RANGE 較大時,該法會跑很慢,一般會將它包成副函式去做

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4. // random(low, up) pick #n, save result to rst
  5. void rand_force(int low, int up, int *rst, int n)
  6. {
  7.     int j, count;
  8.     int range = up-low+1;
  9.     int rnd;
  10.     for(count=0;count<n ; ){
  11.         rnd = rand() % range + low;
  12.         for(j=0; j<count && rst[j]!=rnd; ++j);
  13.         if(j==count) rst[count++] = rnd;
  14.     }
  15. }

  16. int main()
  17. {
  18.     const int low = -5;
  19.     const int  up = 32760;
  20.     const int   N = up-low;

  21.     int rst[32768];
  22.     clock_t ck;
  23.     srand( (unsigned)time(NULL));

  24.     ck = clock();
  25.     rand_force(low,up,rst,N);
  26.     printf("td = %ld\n", clock()-ck);
  27.     return 0;
  28. }


複製代碼
可以跑跑,上面給的例子很極端,所以跑得較慢。

另 rand_force 只有兩點要注意 : (1) range 必須 <= RAND_MAX (2) 適用整數,當然這兩點是可以修正的。

另一種方式叫 shuffle,洗牌法。先產生 int poker[up-low+1],填入數字,再隨機交換。

  1. void shuffle(int low, int up, int *rst, int n)
  2. {
  3.     int rng = up - low + 1;
  4.     int i, pos, t;
  5.     int * poker = (int*) malloc(sizeof(int) * rng);
  6.     for(i=low; i<=up; ++i) poker[i-lower] = i; // generat a poker
  7.     for(i=0; i<rng; ++i){
  8.         pos = rand() % rng;
  9.         t = poker[i], poker[i] = poker[pos] , poker[pos] = t; // swap(poker[i], poker[pos])
  10.     }

  11.     // pick first n from poker to rst
  12.     for(i=0; i<n; ++i) rst[i] = poker[i];
  13.     free(poker);
  14. }
複製代碼
概念上是這樣,洗牌的方式有很多種,但 唯一經過「亂數均勻」測試的是 kunth shuffle,從後面洗回來,這個到 wiki  可以看到說明,就不再附碼了。

另外指標是真的很好用沒錯,但 p[ i ] 和 *(p+i) 其實根本就沒差,在低階 (翻成組語後) 做的事情是一模一樣的。如果有 polling 一份 array的話

  1. int arr[4]  = {1,2,3,4};
  2. for(i=0; i<4; ++i) arr[i];
  3. for(i=0; i<4; ++i) *(arr+i);
複製代碼
這兩個作法是一模一樣的,有差別的是下面這種

  1. int arr[4] = {1,2,3,4};
  2. int *beg = arr , *end = arr+4;
  3. while(beg!=end){
  4.     *beg ; \\ output
  5.     ++beg;
  6. }
複製代碼
這在低階之處理才和上面兩種不同,至於指標其他的作法實在是不勝玫舉,有機會再討論。

一點意見參考,其他再嘴炮的東西 (如設計架構等,這個就見人見智,只是架構規劃的人可以規劃得更好),我就不說了。
回覆

使用道具 舉報

該用戶從未簽到

 樓主| 發表於 2012-11-27 18:36 | 顯示全部樓層
edisonx 發表於 2012-11-27 17:43
來個有建設性的發言好了。

setHidden 是遞迴,但「有機率」會產生 stack overflow 造成程式錯誤。今天換個 ...

感謝edisonx詳細解說
如果遞迴過大 當跑太多次是會溢位沒錯
不過我的需求是
1.方便之後編輯及func.之後還可以用到其他程式
2.不會造成超時(1秒)
ad6543210的程式碼 似乎範圍太大的確會有時間過久的問題
那麼 他說的指標有沒有可能範圍大了以後會有記憶體錯誤的危險性呢!?
回覆

使用道具 舉報

該用戶從未簽到

發表於 2012-11-27 18:46 | 顯示全部樓層
chiayinwang 發表於 2012-11-27 18:36
感謝edisonx詳細解說
如果遞迴過大 當跑太多次是會溢位沒錯
不過我的需求是

如果您的需求是方便編輯、還可以用到其他程式,那你程式碼就不會出現這行

  1. if((ans[1]==ans[3])||(ans[0]==ans[2])||(ans[0]==ans[3])){setHidden(ans);}
複製代碼
如果今天要改成猜 3 個、5 個數字的話不就又要重改了?

至少用 for loop 去做

  1. int rep=0, n=4;
  2. for(i=0; i<n; ++i)
  3.     for(j=i+1; j<n; ++j)
  4.         if(ans[i]==ans[j]) {
  5.             rep = 1;
  6.         }
  7. if(rep) { // do something}
複製代碼
但強調,recursive 的深度有限,太深的話會造成 stack overflow。另外其實用我講的 shuffle,速度並不比 ad6543210 慢多少,除非,(N / RANGE),RANGE 非常大,而 N 非常小,才有明顯差異。

>> ad6543210  說的指標有沒有可能範圍大了以後會有記憶體錯誤的危險性呢!

不可能,除非指標亂用,讀取了不可以讀取的位置、寫入了不可寫入的位置,但有學過指標的人都知道這是基礎,會避開這種錯誤。


點評

感謝你的詳細解說哦!!!  發表於 2012-12-4 17:47
回覆

使用道具 舉報

該用戶從未簽到

發表於 2012-12-1 20:56 | 顯示全部樓層
本帖最後由 csihcs 於 2012-12-1 21:00 編輯

個人覺得可以用抽牌法
此提因為全體量不大。
建議以空間換取時間,
也不需要額外洗牌,
也不需要多餘的檢查。

附註:因為手邊沒有安裝編譯器,
所以有部分內容也許有錯誤。

  1. void setHidden(int* ans,int gainSize) {
  2.   int min = 0, max = 9;
  3.   int remain = max - min + 1;
  4.   int *deck = new int[remain];
  5.   for(int i = min ; i <= max ; ++i) {
  6.     deck[i] = i;
  7.   }

  8.   int gain;
  9.   for(int i = 0 ; i < gainSize; ++i) {
  10.     gain=rand()%remain;
  11.     ans[i] = deck[gain];
  12.     --remain;
  13.     deck[gain] = deck[remain];
  14.   }
  15.   delete deck;
  16. }
複製代碼
回覆

使用道具 舉報

您需要登入後才可以回帖 登入 | 註冊

本版積分規則

小黑屋|Archiver|微剋多資訊(MicroDuo)

GMT+8, 2016-12-8 12:00

Discuz! X

© 2009-2016 Microduo

快速回覆 返回頂部 返回列表