基于实验六对基于时间抽取随机不同数的算法研究
实验报告链接:
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 }
运行:







浙公网安备 33010602011771号