ACM-ICPC 2018 徐州赛区网络预赛 C Cacti Lottery(暴力+期望)

链接https://nanti.jisuanke.com/t/31455

思路

  • 首先先枚举把剩下的数填入星号的情况(其实就是枚举星号的排列),这是对方所能知道的所有信息,然后对方将取八种决策中最优的情况,而因为井号的存在,所以其排列也会影响每种决策的分数,所以接着要枚举井号的排列情况,对于每种情况累加每个决策的分数,最后枚举完后,要除以井号排列数(期望=分数*概率),然后对方便会选择期望最高的决策,累加到最后答案中,枚举完所有星号的之后,需要将最后答案除以星号排列数
#include<bits/stdc++.h>
#define pb push_back
#define M 20
using namespace std;
int G[8][3]={
	{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6},
};
int id[]={0,0,0,0,0,0,10000,36,720,360,80,252,108,72,54,180,72,180,119,36,360,
1080,144,1800,3600};
int tp[M],g[M],p[M],vi[M],tot,i,F[M],Cnt;
double cnt[M],ans;
vector<int>pos;
char s[M];

void ck(){
	vector<int>num;
	for(int i=0;i<8;i++)cnt[i]=0;
	for(int i=1;i<=9;i++){
		if(!vi[i])num.pb(i);
	}
	do{
		int a=0,b=0;
		for(int i=0;i<9;i++){
			if(g[i]>0)tp[i]=g[i];
			else if(g[i]==0)tp[i]=p[a++];
			else tp[i]=num[b++];
		}
		for(int i=0;i<8;i++){
			a=0;
			for(int j=0;j<3;j++){
				a+=tp[G[i][j]];
			}
			cnt[i]+=id[a];
		}
	}while(next_permutation(num.begin(),num.end()));
	double T=0;
	for(int i=0;i<8;i++){cnt[i]=cnt[i]*1.0/F[num.size()];T=max(T,cnt[i]);}
	ans+=T;
}
void dfs(int d){
	if(d==pos.size()){
		Cnt++;
		ck();return;
	}
	for(int i=1;i<=9;i++){
		if(!vi[i]){
			vi[i]=1;p[d]=i;
			dfs(d+1);vi[i]=0;
		}
	}
}
int main(){
	int T;scanf("%d",&T);
	F[0]=F[1]=1;for(i=2;i<=9;i++)F[i]=F[i-1]*i;
	while(T--){
		Cnt=tot=0;ans=0;
		pos.clear();memset(vi,0,sizeof(vi));
		for(int _=0;_<3;_++){
		   scanf("%s",s);for(i=0;i<strlen(s);i++){
			   if(s[i]=='#'){g[tot++]=-1;}
			   else if(s[i]=='*'){pos.pb(tot);g[tot++]=0;}
			   else {g[tot++]=s[i]-'0';vi[s[i]-'0']=1;}
		   }
		}
		dfs(0);
		ans=ans*1.0/Cnt;
		printf("%.7f
",ans);
	}
}

知识点

*暴力求期望:枚举所有情况的总分/所有情况数

原文地址:https://www.cnblogs.com/VIrtu0s0/p/9626113.html