Educational Codeforces Round 13 E 状压dp

来源:互联网 发布:网络舆情办理 编辑:程序博客网 时间:2024/05/18 02:48



链接:戳这里


E. Another Sith Tournament
time limit per test2.5 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
The rules of Sith Tournament are well known to everyone. n Sith take part in the Tournament. The Tournament starts with the random choice of two Sith who will fight in the first battle. As one of them loses, his place is taken by the next randomly chosen Sith who didn't fight before. Does it need to be said that each battle in the Sith Tournament ends with a death of one of opponents? The Tournament ends when the only Sith remains alive.

Jedi Ivan accidentally appeared in the list of the participants in the Sith Tournament. However, his skills in the Light Side of the Force are so strong so he can influence the choice of participants either who start the Tournament or who take the loser's place after each battle. Of course, he won't miss his chance to take advantage of it. Help him to calculate the probability of his victory.

Input
The first line contains a single integer n (1 ≤ n ≤ 18) — the number of participants of the Sith Tournament.

Each of the next n lines contains n real numbers, which form a matrix pij (0 ≤ pij ≤ 1). Each its element pij is the probability that the i-th participant defeats the j-th in a duel.

The elements on the main diagonal pii are equal to zero. For all different i, j the equality pij + pji = 1 holds. All probabilities are given with no more than six decimal places.

Jedi Ivan is the number 1 in the list of the participants.

Output
Output a real number — the probability that Jedi Ivan will stay alive after the Tournament. Absolute or relative error of the answer must not exceed 10 - 6.

Examples
input
3
0.0 0.5 0.8
0.5 0.0 0.4
0.2 0.6 0.0
output
0.680000000000000


题意:

n 个人在打擂台,每次擂台上两个人,输的下场,赢得继续打。

0号可以控制出场顺序以及比赛的输赢

问0号赢得概率


思路:

我无法理解题目求的是啥?是0号赢得最大概率?还是累计0号可以赢得概率算总和?

我是按照0号赢得最大概率来算的,显然0号最后一个上场赢的概率会最大

设置dp(s,i)表示当前状态s下(二进制表示下,1为上场打,0为不打),最后赢得人是j

dp(1,0)=1.0 只有0号一个人在场的时候赢得概率显然是1

转移方程式:dp[i][j]=max(dp[i][j],dp[i-(1<<k)][j]*a[j][k]+dp[i-(1<<j)][k]*a[k][j])

第k个人上场打赢了j或者输了j

状态是倒着推的,所以是k,j先在在场上。


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<string>#include<vector>#include <ctime>#include<queue>#include<set>#include<map>#include<stack>#include<iomanip>#include<cmath>#define mst(ss,b) memset((ss),(b),sizeof(ss))#define maxn 0x3f3f3f3f#define MAX 1000100///#pragma comment(linker, "/STACK:102400000,102400000")typedef long long ll;typedef unsigned long long ull;#define INF (1ll<<60)-1using namespace std;double a[20][20];double dp[300100][20];/// 当前擂台上的人是j,要打赢状态为i的所有人(二进制为1)int n;int main(){    scanf("%d",&n);    for(int i=0;i<n;i++){        for(int j=0;j<n;j++){            scanf("%lf",&a[i][j]);        }    }    dp[1][0]=1.0;    for(int i=0;i<(1<<n);i++){        for(int j=0;j<n;j++){            if((i&(1<<j))==0) continue;            for(int k=0;k<n;k++){                if(j==k || (i&(1<<k))==0) continue;                dp[i][j]=max(dp[i][j],a[j][k]*dp[i-(1<<k)][j]+a[k][j]*dp[i-(1<<j)][k]);            }        }    }    double ans=0.0;    for(int i=0;i<n;i++) ans=max(ans,dp[(1<<n)-1][i]);    printf("%.12f\n",ans);    return 0;}


0 0
原创粉丝点击