- 注册时间
- 2007-12-27
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 40157
- 在线时间
- 小时
|
发表于 2019-11-1 08:48:40
|
显示全部楼层
试着测试一下随机mathe
代码假设Fans给出的目标数据就是按0,1,2,...,N-1顺序给出(但是mathe不知道)
- #include <stdio.h>
- #include <time.h>
- #include <string.h>
- #include <stdlib.h>
- #include <math.h>
- #include <vector>
- #ifndef N
- #define N 20
- #endif
- #define TC 8
- #define TARGET 1
- struct Data{
- char v[N];
- int c;
- };
- std::vector<Data> usedlist;
- std::vector<Data> leftlist;
- char leftc;
- char avail[N][N];
- double tvalue;
- double ve;
- void init()
- {
- tvalue = log(2*M_PI*N)/2+N*(log(N)-1)-log(TARGET);
- ve=exp(-1.0);
- int i,j;
- leftc=N;
- for(i=0;i<N;i++){
- for(j=0;j<N;j++)avail[i][j]=j;
- }
- }
- void dumpleft()
- {
- int i;
- int j;
- for(i=0;i<leftlist.size();i++){
- printf("\n");
- for(j=0;j<N;j++)printf("%d ",leftlist[i].v[j]);
- }
- printf("\n");
- }
- char used[N];
- char mc[N*N];
- char umc[N*N];
- Data tryv;
- int depth;
- void search()
- {
- if(depth>=N){
- leftlist.push_back(tryv);
- return;
- }
- int i,j;
- for(i=0;i<usedlist.size();i++){
- if(mc[i]>usedlist[i].c||umc[i]>N-usedlist[i].c)return;
- }
- for(i=0;i<leftc;i++){
- int k = avail[depth][i];
- if(used[k]==0){//The value has not been used, try use it
- used[k]=1; tryv.v[depth]=k;if(k==depth)tryv.c++;
- for(j=0;j<usedlist.size();j++){
- if(usedlist[j].v[depth]==k){
- mc[j]++;
- }else{
- umc[j]++;
- }
- }
- depth++;
- search();
- depth--;
- for(j=0;j<usedlist.size();j++){
- if(usedlist[j].v[depth]==k){
- mc[j]--;
- }else{
- umc[j]--;
- }
- }
- used[k]=0;if(k==depth)tryv.c--;
- }
- }
- }
- void collect_lefts()
- {
- depth=0;
- tryv.c=0;
- memset(used,0,sizeof(used));
- memset(mc,0,sizeof(mc));
- memset(umc,0,sizeof(umc));
- search();
- }
- int trygenrand(Data& d)
- {
- char cused[N];
- memset(cused,0,sizeof(cused));
- int i,j,k;
- d.c=0;
- for(i=0;i<N;i++){
- j=rand()%leftc;
- int choice=-1;
- for(k=j;k<leftc;k++){
- if(cused[avail[i][k]]==0){choice=k;break;}
- }
- if(choice<0){
- for(k=0;k<j;k++){
- if(cused[avail[i][k]]==0){choice=k;break;}
- }
- }
- if(choice<0)return -1;
- cused[avail[i][choice]]=1;
- d.v[i]=avail[i][choice];
- if(d.v[i]==i)d.c++;
- }
- return 0;
- }
- void genrand(Data& d)
- {
- while(trygenrand(d)<0);
- int i,j;
- usedlist.push_back(d);
- if(d.c==0){
- for(i=0;i<N;i++){
- for(j=0;j<leftc;j++){
- if(d.v[i]==avail[i][j])break;
- }
- if(j>=leftc){
- fprintf(stderr,"Internal error\n");
- exit(-1);
- }
- for(;j<leftc-1;j++){
- avail[i][j]=avail[i][j+1];
- }
- }
- leftc--;
- }
- double dd=ve;for(i=0;i<d.c;i++)dd/=(i+1);
- tvalue+=log(dd);
- }
- int main()
- {
- Data d;
- srand(time(NULL));
- init();
- int t=0;
- while(leftc>TC){
- genrand(d);
- t++;
- }
- printf("try %d times to reach small probability, leftc = %d\n", t, leftc);
- collect_lefts();
- printf("Total %d left\n", (int)leftlist.size());
- dumpleft();
- }
复制代码
测试了含20个数字,而mathe总是瞎猜直到听到12次Fans说你全错了位置在统计余下的可能
每次统计可能会很快(不到一秒)也可能会花费数分钟
试验结果
第一次:
try 72 times to reach small probability, leftc = 8
Total 1 left
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
第二次:
try 57 times to reach small probability, leftc = 8
Total 1 left
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
第三次:
try 53 times to reach small probability, leftc = 8
Total 1 left
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
第四次:
try 48 times to reach small probability, leftc = 8
Total 5 left
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
5 1 12 0 4 19 6 8 17 9 10 3 15 13 14 2 16 7 18 11
5 1 17 0 4 19 6 8 3 9 10 12 15 13 14 2 16 7 18 11
5 1 17 0 14 4 6 8 3 9 11 12 15 13 10 2 16 7 18 19
9 17 12 8 14 0 6 15 4 5 11 3 19 1 10 2 16 7 18 13
于是我们需要补猜一次
5 1 17 * 4 * *************
就可以完全区分了。
第五次:
try 43 times to reach small probability, leftc = 8
Total 2 left
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
0 1 2 3 4 5 6 7 8 13 10 11 12 9 14 15 16 17 18 19
第六次:
try 42 times to reach small probability, leftc = 8
Total 2 left
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
0 1 2 3 4 5 6 7 8 9 19 11 12 13 14 15 16 17 18 10
第七次:
try 56 times to reach small probability, leftc = 8
Total 1 left
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
第八次:
try 70 times to reach small probability, leftc = 8
Total 1 left
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
第九次:
try 61 times to reach small probability, leftc = 8
Total 1 left
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
第十次
try 51 times to reach small probability, leftc = 8
Total 1 left
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
波动还是挺大的。
另外看来随机测试的次数还可以减少,提前分析规律会有好处。只是需要计算力非常强大,mathe远远不够。 |
|