nikeeshi のコーディング記

コーディングの成果をはっつけるとこ。このブログにあるソースコードはNYSL Version 0.9982に従い公開します(2014/06/18)。

コンビネーションとか二項分布とか三分探索とか

まえがき

ちょっとハースストーンで遊んでいたら検証したいことが出てきたので、尤度を計算したよ。

そのときのコードです。何やってたかしりたかったらこっちも見てね ヨグ=サロンは果たして自分のヒーローの呪文を多く選ぶのか? - ふらふらHearthstone

コンビネーションの計算とか二項分布の計算とか三分探索とかやってます。

コンビネーションのdoubleバージョンに関してはある程度大きくなると誤差がでてきます。誤差保証はしていないので、注意してください。

使いたかったらご自由にコピペしてどうぞ。

以下スパゲッティーなコード

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <cassert>
#include <functional>
#include <iomanip>
using namespace std;
class combination
{
    map<pair<int,int>,long long> memo;
    map<pair<int,int>,double> memo_f;
public:
    long long combi(int n, int x) {
        assert(n>=0);
        assert(x>=0&&x<=n);
        if(n==x)return 1;
        else if(x==0) return 1;
        else{
            auto f=memo.find(make_pair(n,x));
            if(f!=memo.end()){
                return (*f).second;
            }else{
                auto res= combi(n-1, x)+combi(n-1, x-1);
                assert(res>=0);
                memo[make_pair(n,x)]=res;
                return res;
            }
        }
    }
    double combi_f(int n, int x) {
        assert(n>=0);
        assert(x>=0&&x<=n);
        if(n==x)return 1;
        else if(x==0) return 1;
        else{
            auto f=memo_f.find(make_pair(n,x));
            if(f!=memo_f.end()){
                return (*f).second;
            }else{
                auto res= combi_f(n-1, x)+combi_f(n-1, x-1);
                assert(res>=0);
                memo_f[make_pair(n,x)]=res;
                return res;
            }
        }
    }
};
long long combi(long long n,long long x){
    static combination c;
    return c.combi(n,x);
}
double combi_f(long long n,long long x){
    static combination c;
    return c.combi_f(n,x);
}
// 確率pのベルヌーイ試行をn回したときにx回出る確率
double nikou(int x,int n,double p){
    return combi_f(n,x)*pow(p,x)*pow(1-p,n-x);
}
struct Yogdata{int x;int n;int myhero;int all;};
double likelihood(vector<Yogdata> data,double mass){
    double ans=1;
    for(auto item:data){
        ans*=nikou(item.x,item.n,item.myhero*mass/(item.myhero*mass+item.all-item.myhero));
    }
    return ans;
}

template<class In,class Out>
void test(Out (*f)(In)){
    In x;
    while(true){
        cin>>x;
        cout<<f(x)<<endl;
    }
}
template<class In1,class In2,class Out>
void test(Out (*f)(In1,In2)){
    In1 x;
    In2 y;
    while(true){
        cin>>x>>y;
        cout<<f(x,y)<<endl;
    }
}
template<class In1,class In2,class In3,class Out>
void test(Out (*f)(In1,In2,In3)){
    In1 x;
    In2 y;
    In3 z;
    while(true){
        cin>>x>>y>>z;
        cout<<f(x,y,z)<<endl;
    }
}
template<class In1,class In2,class Out1,class Out2>
void test(Out1 (*f1)(In1,In2),Out2 (*f2)(In1,In2)){
    In1 x;
    In2 y;
    while(true){
        cin>>x>>y;
        cout<<setprecision(20);
        cout<<f1(x,y)<<"\t"<<f2(x,y)<<endl;
    }
}
double sanbutan(double bn,double ed,double f(double)){
    if(abs(bn-ed)<0.0000001)return bn;
    else{
        double le=(bn*2+ed)/3,ri=(bn+ed*2)/3;
        if(f(le)>=f(ri))return sanbutan(bn,ri,f);
        else return sanbutan(le,ed,f);
    }
}

vector<Yogdata> data;
double wrap(double mass){
    return likelihood(data,mass);
}
void run(){
    int N;
    cin>>N;
    data=vector<Yogdata>(N);
    for(int i=0;i<N;i++){
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        data[i]={a,b,c,d};
    }
    for(int i=0;i<5;i++){
        double mass=i/1.0;
        cout<<mass<<"\t"<<likelihood(data,mass)<<endl;
    }
    cout<<sanbutan(0.0,5.0,wrap)<<endl;
}
int main() {
    run();
}