cf16E Fish(状压DP)

题意:

N只FISH。每个回合会有一只FISH吃掉另一个FISH。直到池塘里只剩一只FISH。

给出aij:第i只FISH吃掉第J只FISH的概率。

问每一只FISH是最后存活者的概率。

Input

The first line contains integer n (1 ≤ n ≤ 18) — the amount of fish in the lake. Then there follow n lines with n real numbers each — matrix aaij (0 ≤ aij ≤ 1) — the probability that fish with index i eats up fish with index j. It's guaranteed that the main diagonal contains zeros only, and for other elements the following is true: aij = 1 - aji. All real numbers are given with not more than 6 characters after the decimal point.

思路:

仔细想想是个DP。N很小,状压DP。。。。

DP方程要推对。【*:写完方程试一两个SAMPLE】

看代码

代码:

int n;
double a[20][20];
double dp[(1<<18)+5];
int STATE[20][(1<<18)+5];
int STATE_n[20];




int calc(int x){
    int res=0;
    rep(i,0,n-1){
        if((x&(1<<i))!=0){
            ++res;
        }
    }
    ret res;
}
void makeState(){
    mem(STATE_n,0);
    int tot=((1<<n)-1);
    rep(i,1,tot){
        int t=calc(i);
        STATE[t][++STATE_n[t]]=i;
    }
}

int main(){

    cin>>n;
    rep(i,0,n-1) rep(j,0,n-1) scanf("%lf",&a[i][j]);

    mem(dp,0);
    dp[(1<<n)-1]=1.0;
    makeState();

    rep2(k,n-1,1){
        int s=-1, _s=-1;
        rep(i,1,STATE_n[k]){ //枚举nowState
            s=STATE[k][i];
            rep(j,0,n-1){
                if((s&(1<<j))==0){
                    _s=s|(1<<j);
                    rep(t,0,n-1){
                        if((s&(1<<t))!=0){
                            dp[s]+=(2*dp[_s]*a[t][j]/(k*(k+1)));
                        }
                    }
                }
            }
        }
    }
    printf("%lf",dp[1]);
    rep(i,1,n-1){
        printf(" %lf",dp[1<<i]);
    }
    cout<<endl;

    ret 0;
}
原文地址:https://www.cnblogs.com/fish7/p/4329988.html