【NOIP2016提高A组模拟7.17】锦标赛

题目

403机房最近决定举行一场锦标赛。锦标赛共有N个人参加,共进行N-1轮。第一轮随机挑选两名选手进行决斗,胜者进入下一轮的比赛,第二轮到第N-1轮再每轮随机挑选1名选手与上一轮胜利的选手决斗,最后只剩一轮选手。第i名选手与第j名选手决斗,第i名选手胜利的概率是a[i][j].
作为一号选手的富榄想知道如何安排每轮出场的选手可以使得他获胜的概率最大,并求出这个最大概率。

分析

(f[i][j])表示剩下的人集合为j,当前胜者为i,我们在向后一轮转移时发现有胜败两种情况,从前向后转会转移入两个状态,这用是不可以的。
所以我们要从后一轮向前一轮转移,把两个状态合入一个状态。

[f_{i,j}=maxleft{egin{array}\f_{i,j-2^{k}}*a_{i,k}+f_{k,j-2^{i}}*a_{k,i}\f_{i,j}end{array} ight. ]

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=50005;
using namespace std;
double f[20][262150],a[20][20],ans;
int n,mi[20],d[20][262150];
int main()
{
	scanf("%d",&n);
	mi[0]=1;
	for(int i=1;i<=n;i++) 
	{
		mi[i]=mi[i-1]*2;
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			scanf("%lf",&a[i][j]);
	for(int i=1;i<=mi[n]-1;i++)
	{
		int j=i,sum=0;
		while(j)
		{
			if(j&1) sum++;
			j/=2;
		}
		d[sum][++d[sum][0]]=i;
	}
	f[1][1]=1;
	for(int i=2;i<=n;i++)
	{
		for(int k=1;k<=d[i][0];k++)
			for(int j=1;j<=n;j++)
				if((d[i][k]&mi[j-1])==mi[j-1])
					for(int l=1;l<=n;l++)
						if((d[i][k]&mi[l-1])==mi[l-1])
							f[j][d[i][k]]=max(f[j][d[i][k]],f[j][d[i][k]-mi[l-1]]*a[j][l]+f[l][d[i][k]-mi[j-1]]*a[l][j]);
	}
	for(int i=1;i<=n;i++)
		ans=max(f[i][mi[n]-1],ans);
	printf("%.7lf",ans);
}
原文地址:https://www.cnblogs.com/chen1352/p/9013526.html