教你如何追求女神

感情迁移 提交于 2020-10-07 17:52:20

教你如何追求女神

点进来的你若以为是PUA教程,请抬头看看论坛名称(明 光 大 正

内卷

计算机学院是我们学校的人口大院

上千的人口、 6 : 1 6:1 6:1的经典失调的男女比例 仅次于机械工程学院

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NUgAdGJx-1601826916971)(./rate.JPG)]

这就使得计院的市场上形成了严重的 内卷效应

像我这样的纯情小生自然是在这种水深火热的环境中被毒打多年

然而,作为一个老二次元,闲来无事到时候逛逛B站,竟从李永乐老师那找到了一些关于恋爱的科学门路

有趣的现象

不知道大家有没有这种经历或是见闻

中学找的对象亦或是初恋,大多分的分,散的散。

能坚持下去的属实凤毛麟角

可是为什么会这样?年轻时的爱情真的这么容易变质吗?

经典问题

苏格拉底曾经给自己的学生出过这样的题目:

倘若有一片麦田,选取其中一列麦子,有个人在这列麦子中捡起一根,并且有如下规则:

  1. 此人不能后退,找前面的麦子
  2. 没有两根相同长度的麦子
  3. 只能捡起一根麦子,捡起就视为结束

苏老师要求学生找到一个方法,找到最长的麦子。

这在学术上被成为 Optimal Stopping Theory

简化问题

我们把恋爱问题套在捡麦子的问题上,把捡麦子的过程换做是女神选择男生的过程,把人简单地按照一维向量排列,也就是说只有排名这种单一的标准来评判男生(多少有点物化男生的味道?)

那么女神通过某种方法,以最大概率,找到最优的男生。

数学分析

参考维基百科

我们设全体男生集合为 M M M

假设现在有三位追求者

M = { 1 , 2 , 3 } M =\{1,2,3\} M={ 1,2,3}

  • 数字表示他们的优秀程度,越优秀数字越大

  • 女神将所有的追求者划分为样本组候选组

  • 女神则是在候选组选择比样本组都要优秀的男生

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bAyApUdi-1601826916975)(./algo01.jpg)]

示例:
对男生做全排列 P P P

排列1 排列2 排列3 排列4 排列5 排列6
1 1 2 2 3 3
2 3 1 3 2 1
3 2 3 1 1 2
  1. 无样本
    • 找到最好(3)的概率为 1 3 \frac{1}{3} 31
  2. 一人做样本
    • 概率为 1 2 \frac{1}{2} 21
  3. 两人做样本
    • 概率为 1 3 \frac{1}{3} 31

可见,这里采用一人做样本的方案是最优的。

推广到一般情况

那么,如果追求者有N个该怎么办呢?

这里涉及到一些概率论与数理统计微积分的知识,觉得头疼的可以跳过

设女神会拒绝前 m − 1 m-1 m1个追求者

那么最优的男生 m m m 将会被选中的概率是:
(贝叶斯定理)

P ( k ) = ∑ m = 1 n P ( m 被 选 中 ∣ m 是 最 优 秀 的 男 生 ) × P ( m 是 最 优 秀 的 男 生 ) P(k)=\sum^{n}_{m=1}P(m被选中|m_是最优秀的男生)\times P(m是最优秀的男生) P(k)=m=1nP(mm)×P(m)

= ( ∑ i = 1 r − 1 0 × 1 n ) + ( ∑ i = r n P ( 仅 次 于 最 优 的 男 生 m − 1 在 候 选 组 中 | m 是 最 优 秀 的 男 生 ) × 1 n ) =(\sum^{r-1}_{i=1}0\times \frac{1}{n})+(\sum^{n}_{i=r}P(仅次于最优的男生m-1在候选组中 | m是最优秀的男生) \times \frac{1}{n} ) =(i=1r10×n1)+(i=rnP(m1m)×n1)

= ∑ i = r n r − 1 m − 1 × 1 n =\sum^{n}_{i=r}\frac{r-1}{m-1}\times \frac{1}{n} =i=rnm1r1×n1

= r − 1 n ∑ i = r n 1 m − 1 = \frac{r-1}{n}\sum^{n}_{i=r}\frac{1}{m-1} =nr1i=rnm11

n − > ∞ n->\infty n> ,
r n = x \frac{r}{n} =x nr=x,

i n = t \frac{i}{n} = t ni=t

1 n = d t \frac{1}{n} = dt n1=dt


P ( x ) = x ∫ x 1 1 t d t = − x l n ( x ) P(x) = x\int_{x}^{1}\frac{1}{t}dt = -xln(x) P(x)=xx1t1dt=xln(x)

P ( x ) P(x) P(x)求导得到 P ′ ( x ) = d P d x P^{'}(x)=\frac{dP}{dx} P(x)=dxdP

P ′ ( x ) = 0 P^{'}(x)=0 P(x)=0

解得 x = 1 e x=\frac{1}{e} x=e1 (约为0.368)

实验证明

算法示意

流程图

Created with Raphaël 2.2.0 开始 提高样本数量 为追求者洗牌 拒绝前k个人 与候选组交往(遍历) 是否大于样本最大值? 选择目前最大 是否达到实验次数? 选择最后一个人 yes no yes no

  1. 我们找一组优秀程度不同的男生,然后随机洗牌,从k人的样本域开始,开始找优秀程度高于样本域最大值的男生,记录一次,视为一次实验。
  2. 结束k人样本域的实验的后,提高样本容量k,重复实验。
  3. 直到k样本数量达到总体候选者的容量后,结束实验

解决问题

作为计算机学院的学生,并且是 Linus 的忠实信徒,坚信

T a l k   i s   c h e a p , s h o w   m e   t h e   c o d e . Talk\ is\ cheap, show\ me\ the\ code. Talk is cheap,show me the code.

就用C++实现了模拟演算

代码如下,自定义的工具函数见附录


std::vector<std::vector<double> > findPossibility(int num_of_samples,int time_of_test){
   
    
    // initialize the list
    // int num_of_samples ;
    
    int *array = nullptr;
    array = generateArray(array, num_of_samples,1);
    
    
    std::vector<std::vector<double> > rs;
    
    for(int i=0;i<num_of_samples;++i)
           rs.push_back(std::vector<double>());

    // vector<int>():创建一个空vector,调用了构造函数
       
       for(int i=0;i<num_of_samples;++i)
           for(int j=0;j<num_of_samples;++j)
               rs[i].push_back(0);

    
    //拒绝前k个
    for(int k = 1 ; k< num_of_samples ; k++){
   
    
        printf("Discard the first %d wheats...\n",k);
        // n 次实验
        for(int i=0; i < time_of_test;i++){
   
    
            
            array = shuffleArray(array, 0, num_of_samples);
            //样本组的最大值
            int max = findGivenMax(array, k);
            //实在没有比前面好的找最后一个
            
            int chosen_one;
            //寻找样本组中最大值
            chosen_one = array[num_of_samples];
                for(int i=k;i<num_of_samples;i++){
   
    
                    if(array[i]>max){
   
    
                        chosen_one = array[i];
                        break;
                    }
                }
           
            
            rs[k][chosen_one] += 1.0 / (double)time_of_test;
        }
    }
    
    return rs;

}

运行结果

这里将结果导出为csv文件
并利用了python numpy与matplotlib等包来绘制结果图
numpy与matplotlib代码见附录

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qZWQscOk-1601826916976)(./graph.png)]

可以看到,大约在样本域大小300 - 400 人左右时达到最大概率。

现象解释

  • 虽然不能完全解释初恋分手的问题原因,但是从这个模型中可以窥见,双方为了寻求更好的伴侣,可能都落入了各自的样本域

总结

算法方面的反思

  • 如果问题只是寻找最优的那个男生的话,不妨采用动态规划(Dynamic Programming)的方法。

生活方面的反思

  • 根据这个模型,男生在追求女神时,要尽量不去踏进她的样本域,并且尽可能提升自己,就能够提高成功率。

  • 现实中的恋爱问题并没有那么简单,它是及其复杂的,比如,还需要考虑到信息不对等、时机把握、多维特征等等。

  • 但是这个问题多少可以为人们在关于选择的问题是提供一定数学上的参考。

  • 人的感情是难以被量化的,遇到了,就请好好把握良机吧。


附录

工具函数

  1. 交换数组元素位置

    //swap
void swap(int &a,int& b){
   
     
        if(a == b)
            return;
        int temp;
        temp =a ;
        a =b;
        b = temp;

}

  1. 工厂模式)产生样本组

int* generateArray(int* array,int n,int mode){
   
     
    array=new int[n];
    //产生全 0 数组
    if(mode==0){
   
     
    
        for(int i = 0 ; i < n ; i++){
   
     
                array[i]=0;
            }
        return array;
    
    }
    //产生有序数组[1,2,3,4,...,n]
    if(mode==1){
   
     
        
        for(int i = 0 ; i < n ; i++){
   
     
                array[i]=i;
        }
        return array;
        
    }
    return nullptr;
}

  1. 洗牌算法(递归)
int* shuffleArray(int* array,int begin,int end){
   
     
    srand(time(NULL)); /*根据当前时间设置“随机数种子”*/

    if(!array){
   
     
        return NULL;
    }
    
    //shuffle
    if(begin>=end)
        return array;
    
    //这里swap在递归前会导致边界保持原状
    shuffleArray(array, begin+1, end);
    swap(array[begin], array[rand()%(end - begin)+begin]);

    
    //return array;
    return array;
}


  1. 找到最大值

    int findGivenMax(int* arr,int range){
   
     
    int max =0;
    
    if(arr==nullptr){
   
     
        return -1;
    }
    
    for(int i = 0 ; i< range ; i++){
   
     
        if(arr[i]>max)
            max=arr[i];
    }
    
    return max;
}

  1. 打印结果

void printResult(){
   
     
    
    std::vector<std::vector<double> > v;
    int n;
    //int num_of_samples,int time_of_test
    std::ofstream outFile;
    outFile.open("/Users/alex/data/data.csv",std::ios::out);
    outFile << "sample"<<","<<"probability"<<std::endl;
    
    
    int n_boy =1000;
    int n_test=1000;
    
    v=findPossibility(n_boy,n_test);
    for(int i =1;i<n_boy;i++){
   
     
        printf("space of sample %d \n",i);
        //for(int j=0;j<100;j++){
   
     
          //  printf("%f ", v[i][j]);
           
        //}
        n = v[i].size()-1;
        
        printf("%f ",v[i][n]);
        printf("\n");
        outFile<<i<<","<<v[i][n]<<std::endl;
    }
    
    outFile.close();
    
    
}


  1. include
#include <stdio.h>
#include <cmath>
#include <time.h>
#include <vector>
#include <fstream>
#include <sstream>
  1. numpy & matplotlib (作图)


import numpy as np
from matplotlib import pyplot as plt 
import csv

print("good")

with open('./data.csv','r') as f:
    reader = csv.reader(f)
    list1,list2 =list(),list()
    for i in reader:
        list1.append(i[0])
        list2.append(i[1])
    x= np.array(list1[1:],dtype='int')
    y= np.array(list2[1:],dtype='float')
    
   # print(x)
    #print(y)
    plt.title("Prove of Wheat Problem")
    plt.xlabel("Number Of Samples")
    plt.ylabel("Probability of Best Choice")
    plt.plot(x,y)
    plt.savefig("graph.png", format="png")
    plt.show()
   

看官们倘若喜欢,别忘了关注我哦!
github的源码

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!