[POJ1487/SERC1998]Single-Player Games

Single-Player Games

题解

第二位贞难调诞生了

其实大体的思路挺好想的,主要是写着字符串处理与高斯消元比较麻烦。

根据每一个数我们是很容易得到一个方程,毕竟它给我们的就是一个方程

我们很容易发现一个括号内的期望值,就是它可以走的儿子的期望值的平均数,我们可以先将后面那一大堆括号化简,得到一个方程,形如a= val+ p_{1}\cdot a+... + p_{26}\cdot z的方程式,我们先将左边的a移动过去,再将右边表示常数的val移动过来,就得到了一个典型的高斯消元的方程式,我们总共有n个这样的方程式,解出来即可。

说一些需要注意的点吧

  • 方程式中的常数读入时可能为负数
  • 总共的值加起来可能爆int
  • 无论是无解还是自由元都要输出undefined
  • 如果一个自由元可以被解出来必须要将其给解出来
  • 因为卡精度可能输出-0.000

反正笔者调了好久才过

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long LL;
const double eps=1e-9;
int n,m,name[30],tot;
double arr[30][30],ans[30];
bool frecnt[30];
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
void swap1(int x,int y,int len){for(int i=1;i<=len;i++)swap(arr[x][i],arr[y][i]);}
int gauss(){
	int t=1,p=1;
	/*for(int i=1;i<=m;i++){
		for(int j=1;j<=n+1;j++)
			printf("%d ",arr[i][j]);
		puts("");		
	}*/
	for(;p<=m&&t<=m;p++,t++){
		int maxx=p;
		for(int j=p;j<=m;j++)
			if(Fabs(arr[j][t])>Fabs(arr[maxx][t]))
				maxx=j;
		if(p!=maxx)swap1(p,maxx,n+1);
		if(Fabs(arr[p][t])<eps){p--;continue;}
		for(int j=p+1;j<=m;j++){
			if(Fabs(arr[j][t])<eps)continue;
			double tmp=arr[j][t]/arr[p][t];
			for(int k=t;k<=n+1;k++)
				arr[j][k]-=arr[p][k]*tmp;
		}
	}
	for(int i=p;i<=m;i++)if(Fabs(arr[i][t])>eps)return -1;
	if(p<=m){
		int num=0,freidx;
		for(int i=p-1;i>0;i--){
			num=0;double tmp=arr[i][n+1];
			for(int j=1;j<=n;j++)
				if(Fabs(arr[i][j])>eps&&frecnt[j])
					num++,freidx=j;
			if(num>1)continue;tmp=arr[i][n+1];
			for(int j=1;j<=n;j++)
				if(Fabs(arr[i][j])>eps&&j!=freidx)
					tmp-=arr[i][j]*ans[j];
			ans[freidx]=tmp/arr[i][freidx];frecnt[freidx]=0;
		}
		return m-p+1;
	}
	for(int i=m;i>0;i--){
		double tmp=arr[i][n+1];
		for(int j=i+1;j<=n;j++)
			tmp-=arr[i][j]*ans[j];
		ans[i]=tmp/arr[i][i];
	}
	return 0;
}
double sum[200],sa[200][30];
int cnt[200],num;
char ch[250];
signed main(){
	while(scanf("%d",&n)!=EOF&&n){
		memset(arr,0,sizeof(arr));getchar();
		memset(name,0,sizeof(name));
		memset(ans,0,sizeof(ans));
		memset(frecnt,1,sizeof(frecnt));
		for(int i=1;i<=n;i++){
			memset(sum,0,sizeof(sum));
			memset(sa,0,sizeof(sa));
			memset(cnt,0,sizeof(cnt));
			gets(ch);name[i]=ch[0]-'a'+1;
			bool flag=false;num=0;
			int id=1,len=(int)strlen(ch);
			while(id<len){
				//printf("%d:%c %d\n",++siz,ch,num);
				bool af=false;;
				if(ch[id]=='(')cnt[num]++,num++,id++,flag=af=1;
				if(ch[id]==')'){
					double tmp=sum[num]/(1.0*cnt[num]);
					for(int i=1;i<=n;i++){
						sa[num-1][i]+=sa[num][i]/(1.0*cnt[num]);
						sa[num][i]=0;	
					}
					cnt[num]=sum[num]=0;af=1;
					num--;sum[num]+=tmp;id++;
				}
				if(('0'<=ch[id]&&ch[id]<='9')||ch[id]=='-'){
					LL x=0,f=1;af=1;
					while(('0'<=ch[id]&&ch[id]<='9')||ch[id]=='-'){
						if(ch[id]=='-')f=-1;
						else x=x*10ll+(ch[id]-'0');
						id++;if(id>=len)break;
					}
					x*=f;cnt[num]++;sum[num]+=x;
				}
				if('a'<=ch[id]&&ch[id]<='z'){
					int nam=ch[id]-'a'+1;sa[num][nam]++;
					cnt[num]++;id++;af=1;
				}
				if(!af)id++;
			}
			sa[0][name[i]]--;
			for(int j=1;j<=n;j++)arr[i][j]=sa[0][j],sa[0][j]=0;
			arr[i][n+1]=-sum[0];
		}
		m=n;int ak=gauss();printf("Game %d\n",++tot);
		for(int i=1;i<=n;i++){
			if(Fabs(ans[i])<eps)ans[i]=0;
			if(ak==-1||(ak>0&&frecnt[i]))
				printf("Expected score for %c undefined\n",name[i]+'a'-1);
			else printf("Expected score for %c = %.3f\n",name[i]+'a'-1,ans[name[i]]);
		}
		puts("");
	}
	return 0;
}

谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值