Javaは微信のお年玉の分配のアルゴリズムを実現します


お年玉アルゴリズム分析
他のブログでは、多くの人が自分の観点を提出しており、私はそのアルゴリズムを選んで分析しています.例えば、お年玉を奪う額は0.01から残りの平均値*N(Nは係数で最大のお年玉値を決める)の間で、例えば全部で10元を出して、10個のお年玉を出しました:最初の人は(0.01~1*N)の間のお年玉の値を手に入れることができて、もちろんすべての人が少なくとも1銭持っていることを確保するために、前の数人はお金を全部持ってはいけません.そのため、判断アルゴリズムが必要です.例えば、誰もが自分の最大値を持っている場合:
public class test{
    public static void main(String[] args)
    {   
        float num=10,N=1.9f;//       1.9
        int people=10;
        for(int i=0;i<10;i++)
        {
            System.out.println("the number"+people+" can get  "+ num/people*N);
            num=num-num/people*N;
            people--;
        }
        System.out.println("there remain"+num);
    }   

}

その結果、10人が終わった後、残りのお金はマイナスで、最後の人が彼の最大値に達しないことを示しています.もし私たちが係数を2.3に変更したら、
number 1が負数になっていることが分かったが,これも明らかに不適切であるため,係数のアルゴリズムを用いる場合には,金額が妥当か否かを判断する追加が重要である.
2.2設定金額の上下限
私たちのお年玉の金額は少なくとも0.01で、最大200(単一のお年玉の金額は200を超えない)があります.もしランダムに出てきたデータがこの範囲内でなければ、明らかに間違いです.お年玉の最小金額と最大金額をそれぞれ設定します.
private static final float MINMONEY =0.01f;  
private static final float MAXMONEY =200f;

2.3金額が合法かどうかを判断する
金額が最大値を超えたり、最小値を下回ったりした場合、明らかに間違っています.また、各人がランダムな金額を暫定した後も、残りの金額が合法かどうかを判断します.
private boolean isRight(float  money,int count)
{
  double avg = money/count;
  if(avgreturn false;
  }
  else if(avg>MAXMONEY)
  {
    return false;
  }
  return true;
}

2.4ランダムにお年玉を出す
今ではランダムな方法でMINMONEYからMAXONEYの間のお年玉を生成し、このお年玉を生成した後、数値が合理的かどうかを分析する必要があります.残りのお金はマイナスになったのではないでしょうか.生成されたお年玉が適切でなければ、分配案を再生成します.また、お年玉の値を考える必要があります.今回のデータが小さすぎると、次は大きな値が生まれ、逆も同じです.
private float randomRedPacket(float money,float mins,float maxs,int count)
{
  if(count==1)
  {
    return (float)(Math.round(money*100))/100;
  }
  if(mins == maxs)
  {
    return mins;//           ,   mins
  }
  float max = maxs>money?money:maxs;
  float one = ((float)Math.random()*(max-mins)+mins);
  one = (float)(Math.round(one*100))/100;
  float moneyOther = money - one;
  if(isRight(moneyOther,count-1))
  {
    return one;
  }
  else{
    //    
    float avg = moneyOther / (count-1);
    if(avgreturn randomRedPacket(money,mins,one,count);
    }else if(avg>MAXMONEY)
    {
      return randomRedPacket(money,one,maxs,count);
    }
  }
  return one;
}

2.5お年玉の配分を実現する
1つのお年玉が大量の資金を占有することを避けるために、最後のお年玉ではない最大金額を設定し、平均値のN倍に設定することができ、前の方法に基づいてお年玉の配分を実現することができます.
private static final float TIMES = 2.1f;

public List splitRedPackets(float money,int count)
{
  if(!isRight(money,count))
  {
    return null;
  }
  List list = new ArrayList();
  float max = (float)(money*TIMES/count);

  max = max>MAXMONEY?MAXMONEY:max;
  for(int i=0;ifloat one = randomRedPacket(money,MINMONEY,max,count-i);
    list.add(one);
    money-=one;
  }
  return list;
}

2.6主関数の作成
main関数で具体的な操作を行います.
 public static void main(String[] args) {  
        RedPacketUtil util = new RedPacketUtil();  
        System.out.println(util.splitRedPackets(200, 100));  
    }  
}

完全なコード取得方法は1.5節を参照し、Xfce端末でコードを実行する.
javac RedPacketUtil.java
java RedPacketUtil

実験棟での運行結果は下図の通りである.
三、分析データ
3.1シミュレーション回数を増やす
このお年玉の分配アルゴリズムはネットユーザーたちが推測しているので、しばらく微信がそうしているかどうかを考えないで、私たちはこのアルゴリズムについて分析することができて、シミュレーションの回数が500回、1000回の時、すべての人が得ることができる金額、私たちはこの計算結果を得ることができます.ツールクラスライブラリjava.util.Scannerを、前節の実験の完全なコードにインポートします.
import java.util.Scanner;

同時にmain関数を書き換えます.numはシミュレーションの回数で、NUMは人数です.
public static void main(String[] args) {     
        System.out.println("please input a number");  
        Scanner sc=new Scanner(System.in);
        int num = sc.nextInt(),count = num,NUM=20;
        float[] index = new float[NUM];
        while(num-->0)
        {
            RedPacketUtil util = new RedPacketUtil();  
            List temp = util.splitRedPackets(20, NUM); 
            for(int i=0;iget(i);
            }
        }
        for(int i=0;iout.println("the number "+i+" can get "+(index[i]/count));
        }
    }

私たちがシミュレートしたのは20元のお年玉で、20人に分けて、10回運行して、得た結果:
データは特にありませんが、実行回数が1000000回に達した場合:
このような効果は、私たちのアルゴリズムにすぎません.
3.2人数を増やせば、どんな変化があるのだろうか.
main関数のコードを変更し、人数を200人に増やし、100000回シミュレーションします.
後ろに偏った人が大きなお年玉をもらう確率はかなり低いことがわかります.