基于实验六对基于时间抽取随机不同数的算法研究

实验报告链接:

https://www.cnblogs.com/nnn13579/p/10992122.html

 

对于基于时间抽取不同数,容易出现:

 

这是某位同学的实验结果。

当中使用了这样的语句:

srand((unsigned)time(NULL));

和下面这条是一个效果:

srand((int)time(0));

问题就出在这里。

原因很简单,计算机运算速度很快,精确到秒对于计算机来说太大了。

那么将int改成double是否有效解决呢?

No,除非你用的是Linux系统的php,精确到毫秒。

而且当要抽的量大时,也可能重复。

所以我的第一想法是,当重复时,直接全部重抽好了。

所以有了如下代码:

 1     int k=0;
 2     do{
 3         srand((int)time(0));
 4         for(int i=0;i<n;i++)
 5             luck[i]=rand()%num;
 6         for(int i=0;i<n;i++)
 7             for(int j=i+1;j<n;j++)
 8                 if(luck[i]==luck[j]){
 9                     k=1;break;
10                 }
11     }while(k);

 

通过检测是否有抽出了相同数来确定是否重抽。

但显然,这种做法效率低下。

于是考虑在抽出相同数时,反复更改抽出的数来确保没有相同数。

于是:

 1 for(int i=0;i<n;i++){
 2     srand((double)time(0));
 3     luck[i]=rand()%num;
 4     int j=0,k=0;
 5     for(;j<i;j++)
 6         if(luck[i]==luck[j]){
 7             k=1;
 8             while(k){
 9                 srand((double)time(0));
10                 luck[i]=rand()%num;
11                 if(luck[i]!=luck[j]) {
12                     int t=0;
13                     for(;t<i;t++)
14                         if(luck[t]==luck[i]) break;
15                     if(t==i) k=0;
16                 }
17             }
18         }
19 }

 

但是,当抽40人时,起码要40+s,

效率低下的问题依旧没有解决。

那么优化算法,利用C(n)(m)=C(m-n)(m),增添以下内容:

 1  if(n<=num/2||n<=num/2+1){
 2         fun1(luck,n,date,num);
 3         fun2(luck,n);
 4     }
 5     else{
 6         int tluck[num-n];
 7         fun1(tluck,num-n,date,num);
 8         fun2(tluck,num-n);
 9         int tluckn=0,luckn=0;
10         for(int i=0;i<n;i++){
11             while(luckn==tluck[tluckn])
12                 luckn++;
13             luck[i]=luckn;
14             luckn++;
15         }
16     }

 

fun1()为抽取随机数的函数,fun2()为排序抽取的数。

但这治标不治本。

问题在哪里呢?

出在会抽出重复数。

对于抽n个数,极大可能抽了不止n次。

于是我有了一个想法,把抽过的数全部排除掉,然后在剩下数中抽取。

 1 void fun1(int luck[],int n,int num,int i,int all[]){
 2     if(i<n){
 3         srand((double)time(0));
 4         int t=rand()%num;
 5         luck[i]=all[t];
 6         for(int j=t;j<num-1;j++)
 7             all[j]=all[j+1];
 8         fun1(luck,n,num-1,i+1,all);
 9     }
10 }
11 ……
12 ……
13 ……
14 int all[num];
15 for(int i=0;i<num;i++)
16     all[i]=i;
17 fun1(luck,n,num,0,all);

 

all[]用于存储所有人的序号,

每个人的序号都有两种,

一种是在班里的序号,

另一种是在数组中的“房间号”。

而我们每次抽的都是房间号。

每次抽一个人后,将这个人踢掉,然后剩下的人一次向前移一个“房间”填补空位,实现房间里的人更新。

之后再用抽剩的人去抽下一轮。

由于

int t=rand()%num;

中,num值一直在变,随机的数也会一直变化,实现刷新。

即便一直抽取同一个“房间”,例如1号房,

但由于房间里的人已经换过了,所以不会是抽出同一人。

经过这次算法优化,能够实现抽n人只需要抽n次,抽取40人的时间压缩到了1s内。

 

注:

在没终极优化之前,这个为了防误以为卡机的小程序段挺好玩的:

 1 void fun1(int luck[],int n,char date[],int num){
 2     for(int i=0;i<n;i++){
 3         cout<<"输 出文件名:"<<date<<endl;
 4         cout<<"列 表生成中,已完成"<<(int)((double)i/(double)n*100.0)<<"%\n";
 5         luck[i]=rand()%num;
 6         int j=0,k=0;
 7         for(;j<i;j++)
 8             if(luck[i]==luck[j]){
 9                 k=1;
10                 while(k){
11                     srand((double)time(0));
12                     luck[i]=rand()%num;
13                     if(luck[i]!=luck[j]) {
14                         int t=0;
15                         for(;t<i;t++)
16                             if(luck[t]==luck[i]) break;
17                         if(t==i) k=0;
18                     }
19                 }
20             }
21         system("cls");
22     }
23 }

 

再加个进度条:

 1 per/=2;
 2 for(int z=0;z<53;z++)
 3     cout<<"=";
 4 cout<<endl;
 5 cout<<"|";
 6 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);
 7 for(int z=0;z<=per;z++)
 8     cout<<"*";
 9 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_BLUE);
10 for(int z=per+1;z<51;z++)
11     cout<<"*";
12 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
13     cout<<"|"<<endl;
14 for(int z=0;z<53;z++)
15     cout<<"=";
16 cout<<endl;

 

完整代码:

  1 #include <iostream>
  2 #include <string>
  3 #include "utils.h"
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <fstream>
  7 #include <ctime>
  8 #include "windows.h"
  9 using namespace std;
 10 
 11 void fun1(int luck[],int n,char date[],int num);//生成随机数 
 12 void fun2(int luck[],int n);//升序排序 
 13 
 14 void fun1(int luck[],int n,char date[],int num){
 15     for(int i=0;i<n;i++){
 16         cout<<"输 出文件名:"<<date<<endl;
 17         int per= (int)((double)(i+1)/(double)n*100.0);
 18         cout<<"列 表生成中,已完成"<<per<<"%\n";
 19         per/=2;
 20         for(int z=0;z<53;z++)
 21             cout<<"=";
 22         cout<<endl;
 23         cout<<"|";
 24         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);
 25         for(int z=0;z<=per;z++)
 26             cout<<"*";
 27         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_BLUE);
 28         for(int z=per+1;z<51;z++)
 29             cout<<"*";
 30         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
 31         cout<<"|"<<endl;
 32         for(int z=0;z<53;z++)
 33             cout<<"=";
 34         cout<<endl;
 35         luck[i]=rand()%num;
 36         int j=0,k=0;
 37         for(;j<i;j++)
 38             if(luck[i]==luck[j]){
 39                 k=1;
 40                 while(k){
 41                     srand((double)time(0));
 42                     luck[i]=rand()%num;
 43                     if(luck[i]!=luck[j]) {
 44                         int t=0;
 45                         for(;t<i;t++)
 46                             if(luck[t]==luck[i]) break;
 47                         if(t==i) k=0;
 48                     }
 49                 }
 50             }
 51         if(per==50) system("pause");
 52         system("cls");
 53     }
 54 }
 55 
 56 void fun2(int luck[],int n){
 57     for(int i=0;i<n;i++){
 58         int min=i;
 59         for(int j=i+1;j<n;j++)
 60             if(luck[min]>luck[j]) min=j;
 61         if(min!=i){
 62             int t=luck[min];
 63             luck[min]=luck[i];
 64             luck[i]=t;
 65         }
 66     }
 67 }
 68 
 69 int main() {
 70     
 71     SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
 72     
 73     string filename;
 74     
 75     filename = getCurrentDate();
 76     
 77     cout << "日 期:" << filename << endl;
 78     
 79     char file1[100];
 80     cout<<"请 输入文件:";
 81     gets(file1);
 82 
 83     ofstream fout;
 84     ifstream fin;
 85     fin.open(file1);
 86     while(!fin.is_open()){
 87         cerr << "打 开文件 " << file1 <<" 失败!"<< endl;
 88         system("pause");
 89         cout<<"请 重新输入文件: ";
 90         gets(file1);
 91         fin.open(file1);
 92     }
 93     
 94     int num=0;
 95     string a[1000];
 96     ifstream infile(file1);
 97     while(!infile.eof()){
 98         getline(infile,a[num],'\n');
 99         num++;
100     }
101     
102     int n;
103     cout<<"请 输入抽取人数:";
104     cin>>n;
105     while(n>num){
106         cout<<"抽 取人数超过名单人数!"<<endl; 
107         cout<<"请 重新输入抽取人数:";
108         cin>>n;
109     }
110     
111     char date[100];
112     strcpy(date,filename.c_str());
113     char *txt=".txt";
114     strcat(date,txt);
115     fout.open(date);
116     if(!fin.is_open()){
117         cerr << "生 成失败! " << date << endl;
118         system("pause");
119         exit(0);
120     }
121     
122     system("cls");
123     int luck[n];
124     srand((double)time(0));
125     if(n<=num/2||n<=num/2+1){
126         fun1(luck,n,date,num);
127         fun2(luck,n);
128     }
129     else{
130         int tluck[num-n];
131         fun1(tluck,num-n,date,num);
132         fun2(tluck,num-n);
133         int tluckn=0,luckn=0;
134         for(int i=0;i<n;i++){
135             while(luckn==tluck[tluckn])
136                 luckn++;
137             luck[i]=luckn;
138             luckn++;
139         }
140     }
141 
142     cout<<"输 出文件名:"<<date<<endl;
143     for(int i=0;i<n;i++){
144         fout<<a[luck[i]]<<endl;
145         cout<<a[luck[i]]<<endl;
146     }
147 
148     fin.close();
149     fout.close();
150     return 0;
151 }
main.cpp

 

运行:

 

 

 

 

posted @ 2019-06-11 21:38  淳简拉基茨德  阅读(336)  评论(0)    收藏  举报