• Codeforces 678E. Another Sith Tournament(概率DP,状压)


    Codeforces 678E. Another Sith Tournament

    题意:

    n(n<=18)个人打擂台赛,给定任意两人对决的胜负概率,比赛规则:可指定一人作为最开始的擂主,每次可指定台下的人替代失败的人上去对决,失败的人出局。问在最优决策下,第一个人留到最后的概率。

    思路:

    首先要观察到这一性质:一号玩家要想取得最终胜利的概率尽可能大,一定要把他安排在最后上场,只打一次。获胜概率与当前擂主以及台下的人有关,所以这个是状态,容易想到需要用二进制表示来压缩状态。
    然而想到这些还是不好做,因为如果顺着逻辑正向DP是很困难的,因为每次有输和赢两种走向。因此需要倒着DP。
    那么,定义dp[i][sta]:当前存活状态为sta,擂主为i的情况下,一号玩家获胜的最大概率。那么就有了这般转移式:
    dp[i][sta] = max{ dp[i][sta], p[i][j] * dp[i][sta^(1<<j)] + p[j][i] * dp[j][sta^(1<<i)] }
    这个转移式不是很好理解,想了比较久,觉得这样理解比较好:
    对于擂主为i,存活人状态为sta的情况,枚举下一个上台的人j,对于确定的j,状态就有两种走向,i打败j或j打败i。
    因此如果我们的决策是指定j上台攻擂,那么上述状态下一号玩家获胜的概率就会等于
    pij(i赢j的概率) * dp[i]sta^(1<<j) + pji(i输给j的概率) * dp[j]sta^(1<<i)

    因此DP转移的顺序应该是倒着的,对于确定的存活状态,再枚举擂主以及攻擂的人,来贪心出怎么转移过去一号玩家获胜概率最大,那么倒着推到n个人都活着的时候,对擂主i枚举,即可贪出最大概率。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<iomanip>
    #include<vector>
    #include<map>
    #include<set>
    #include<queue>
    #include<cstring>
    #include<cmath>
    #include<functional>
    #include<string>
    #define dd(x) cout<<#x<<" = "<<x<<" "
    #define de(x) cout<<#x<<" = "<<x<<"
    "
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef pair<int,int> P;
    typedef priority_queue<int> BQ;
    typedef priority_queue<int,vector<int>,greater<int> > SQ;
    const int maxn=6e5+10,mod=1e9+7,INF=0x3f3f3f3f;
    ld p[20][20];
    ld dp[20][maxn];
    int main()
    {
    	int n;
    	cin>>n;
    	for (int i=0;i<n;++i)
    		for (int j=0;j<n;++j)
    			cin>>p[i][j];
    	dp[0][1]=1;
    	for (int sta=1;sta<(1<<n);++sta) 
    	{
    		for (int i=0;i<n;++i) 		
    		{
    			if (!(sta&(1<<i)))
    				continue; 			
    		 	for (int j=0;j<n;++j)	
    		 	{
    		 		if (i==j||!(sta&(1<<j)))
    		 			continue;
    		 		dp[i][sta]=max(dp[i][sta], p[i][j]*dp[i][sta^(1<<j)]+p[j][i]*dp[j][sta^(1<<i)]);
    		 	}
    		 }
    	}
    	ld ans=-1;
    	for (int i=0;i<n;++i)
    		ans=max(ans,dp[i][(1<<n)-1]);
    	cout<<setprecision(10)<<ans;
    	return 0;
    }
    
  • 相关阅读:
    图灵访谈之二十二——Brian W. Kernighan与CS的半个世纪 (翻译)
    GIT 初探
    关于SQL的分组汇总统计(关键字 Grouping)
    根据表名生成该表的插入语句
    利用sys.dm_db_index_physical_stats查看索引碎片等数据
    SQL SERVER CURSOR
    Configuring a readonly replicated folder on Windows Server 2008 R2.
    securestring
    Sql Server查询性能优化
    七大排序速查版
  • 原文地址:https://www.cnblogs.com/orangee/p/9844279.html
Copyright © 2020-2023  润新知