题目大意: 给一棵递归树,看链接图片,从根节点开始对于每个节点往它的子节点移动,直到叶子节点停止。每个节点选哪一个孩子节点继续往下走是随机的(等概率)。然后叶子节点都会标记一个数值,记为走到该节点的得分。

输入条件:先输入整数n(n=0时结束),接下来有n行(n <= 26),每一行会为前n个小写字母(每个字母作为一个变量)的描述。如a = (1 b)表示 f(a) = 1/2 * (1 + f(b))其中f(x)为x节点的得分期望。

现在对n个小写字母表示的变量节点,求出那个节点的得分期望即f(x) (x=a,b,c ...)。

这个题相当有意思,有意思在于它的输入——基于某个字符集的语义分析。递归向下分析的策略,而且是非常典型LL(1)文法!

S -> XWEWT

X -> (X)|a|b|c|...|z

E -> '='

W -> {Blank}|空

T -> (U)

U -> T|X|I

U -> UwU

w ->  {Blank}

I -> [+|-]{Digit}+[.{Digit}]

这道题另外一个关键点是将T转化成方程式,然后综合这n个方程式,使用gauss消元求解。

gauss消元其实就是线性代数中,化简行列式然后进行求解。不会的亲们回去好好看看线性代数的书,不要看网上某些人写的不清不楚的报告。

只是有一点需要注意:计算机中的数字是有界的,要时刻注意数字边界问题!

还有,很多事情需要自己亲身实践,我贡献了很多次WA,一个大原因是听人家要排除输出"-0.000"的问题。

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
int alpha[]={},n;
int getint(char *mes){
int i=;
while(mes[i]!='\0' && (mes[i]<'' || mes[i]>'')) i++;
return atoi(mes+i);
}
struct equation{
double ec[];
equation(){ for(int i=;i<;i++) ec[i]=; }
equation operator+(const equation & S){ equation E; for(int i=;i<;i++) E.ec[i]= ec[i]+S.ec[i]; return E; }
equation operator+=(const equation & S){ for(int i=;i<;i++) ec[i]+=S.ec[i]; return *this; }
equation operator*(double rat){ equation E; for(int i=;i<;i++) E.ec[i]= ec[i]*rat; return E; }
void print(){ for(int i=;i<n-;i++) printf("%f*%c + ",ec[i],i+'a'); printf("%f*%c = %f\n",ec[n-],n-+'a',ec[]); }
};
char mes[]; int idx;
equation getEquation(){
equation E;
if(mes[idx] == '('){
queue<equation> que; idx++;
while(){
while(!alpha[mes[idx]]) idx++; //跳到下一个合法字母
if(mes[idx]==')') break;
que.push(getEquation());
} idx++;
double quesize=1.0/que.size();
while(!que.empty()) E += que.front()*quesize, que.pop();
}else if(mes[idx]>=''&&mes[idx]<='' || mes[idx]=='-' || mes[idx]=='+'){
double t=,sign=;
if(mes[idx]=='-' || mes[idx]=='+'){
if(mes[idx]=='-') sign=-;
idx++;
}
while(mes[idx]>=''&&mes[idx]<=''){
t = t* + mes[idx]-'';
idx++;
}
if(mes[idx]=='.'){
double tt=0.1; idx++;
while(mes[idx]>=''&&mes[idx]<=''){
t += tt*(mes[idx]-'');
tt *= 0.1; idx++;
}
}
//printf("t = %f, sign = %f\n",t,sign);
E.ec[]=t*sign;
}else { // 'a' ---- 'z'
E.ec[mes[idx]-'a']=;
idx++;
}
while(!alpha[mes[idx]]) idx++; //跳到下一个合法字母
return E;
}
equation parse(){
while(mes[idx]<'a' || mes[idx]>'z') idx++;
int c=mes[idx]-'a';
while(mes[idx]!='=') idx++; idx++;
while(!alpha[mes[idx]]) idx++; //跳到下一个合法字母
equation E = getEquation();
E.ec[]=-E.ec[];
E.ec[c]-=;
return E;
}
double mat[][];
int setted[],rid[];
const double zero=1e-;
void unset(int x){
if(!setted[x]) return;
setted[x]=;
for(int i=x-;i>=;i--)
if(fabs(mat[i][x]) > zero)
unset(i);
}
void gauss(){
memset(setted,-,sizeof(setted));
for(int r=;r<n;r++){
int c=r;
int nonzero=-; double minv=1e99;
for(int i=c;i<n;i++)
if(fabs(mat[i][c]) > zero && fabs(mat[i][c]-) < minv)
nonzero=i, minv=mat[i][c];
if(nonzero < ) unset(r);
else {
double rat=/mat[nonzero][c];
for(int i=c;i<=n;i++) mat[nonzero][i] *= rat, swap(mat[nonzero][i],mat[r][i]);
for(int i=;i<n;i++)
if(i!=r && fabs(mat[i][c]) > zero){
rat = mat[i][c];
for(int j=c;j<=n;j++)
mat[i][j] -= rat*mat[r][j];
}
}
}
}
int main()
{
// init the legal alpha
for(int i='';i<='';i++) alpha[i]=;
for(int i='a';i<='z';i++) alpha[i]=;
alpha['.']=; alpha['(']=; alpha[')']=;
alpha['+']=; alpha['-']=;
// main logic
int game=;
do {
gets(mes); n=getint(mes);
if(n <= ) break;
for(int i=;i<n;i++){
gets(mes); idx=;
equation E = parse();
//E.print();
for(int j=;j<;j++)
mat[i][j]=E.ec[j];
}
for(int j=;j<n;j++)
mat[j][n]=mat[j][];
printf("Game %d\n",game++);
gauss();
for(int j=;j<n;j++)
if(setted[j]) {
/* 排除输出 -0.000 的问题, 这里多余了
int tt=0;
for(int i=0;i<n;i++){
sprintf(mes,"%.3f",mat[j][n]);
tt=0;
if(memcmp("-0.000",mes,5)==0) tt=1;
printf("Expected score for %c = %s\n",j+'a',mes+tt);
}
*/
printf("Expected score for %c = %.3f\n",j+'a',mat[j][n]);
}
else printf("Expected score for %c undefined\n",j+'a');
puts("");
}while();
return ;
}

poj1487的更多相关文章

  1. POJ1487 Single-Player Games 高斯消元

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ1487 题解概括 给出多个树形结构,由小写字母和数字表示,每个小写字母表示一棵小树.现在,以a为根节点 ...

  2. poj分类 很好很有层次感。

    初期: 一.基本算法:      (1)枚举. (poj1753,poj2965)      (2)贪心(poj1328,poj2109,poj2586)      (3)递归和分治法.      ( ...

  3. 【转】POJ题目分类推荐 (很好很有层次感)

    OJ上的一些水题(可用来练手和增加自信) (poj3299,poj2159,poj2739,poj1083,poj2262,poj1503,poj3006,poj2255,poj3094)初期: 一. ...

  4. 【转】ACM训练计划

    [转] POJ推荐50题以及ACM训练方案 -- : 转载自 wade_wang 最终编辑 000lzl POJ 推荐50题 第一类 动态规划(至少6题, 和 必做) 和 (可贪心) (稍难) 第二类 ...

  5. POJ 题目分类(转载)

    Log 2016-3-21 网上找的POJ分类,来源已经不清楚了.百度能百度到一大把.贴一份在博客上,鞭策自己刷题,不能偷懒!! 初期: 一.基本算法: (1)枚举. (poj1753,poj2965 ...

  6. (转)POJ题目分类

    初期:一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推. ...

  7. acm常见算法及例题

    转自:http://blog.csdn.net/hengjie2009/article/details/7540135 acm常见算法及例题  初期:一.基本算法:     (1)枚举. (poj17 ...

  8. poj分类

    初期: 一.基本算法:      (1)枚举. (poj1753,poj2965)      (2)贪心(poj1328,poj2109,poj2586)      (3)递归和分治法.      ( ...

  9. 转载 ACM训练计划

    leetcode代码 利用堆栈:http://oj.leetcode.com/problems/evaluate-reverse-polish-notation/http://oj.leetcode. ...

随机推荐

  1. jQuery 网格布局插件

    如今,大多数网站设计要靠网格系统和布局,这能够提供给设计人员一个方便的途径来组织网页上的内容.网格的设计最常见于报纸和杂志的版面,由文字和图像构成的列组成. 这篇文章给大家分享精心挑选的15款最佳的 ...

  2. SqlDataAdapter.Update()方法与SqlCommandBuilder(转)

    用SqlDataAdapter操纵数据集时最常用到的就是Fill()与Update()方法.Fill()填充DataSet或DataTable,而Update()就是将DataSet或DataTabl ...

  3. ARP网关占用

    30网段已经发生了2次ARP了 排查方法:我直去核心交换机直连镜像口,用wireshark抓包,过滤出ARP的包 发现的确有ARP的攻击,因为没有统计公司电脑和无线路由的MAC地址,所以只能一个个把无 ...

  4. poj2752Seek the Name, Seek the Fame

    Description The little cat is so famous, that many couples tramp over hill and dale to Byteland, and ...

  5. Linux下进程的文件访问权限

    本文转自 http://blog.csdn.net/chosen0ne/article/details/10581883 对进程校验文件访问权限包括两个部分,一是确定进程的角色(属于哪个用户或者组), ...

  6. C++ buffer缓冲区的秘密

    在搞数据库和C++进行连接的时候,遇到一个问题,就是如果前面用到了fflush(stdin)即清空缓冲区,就OK,如果不清空缓冲区就不能把记录加入到Mysql的数据库中, 但是即便如此,这个问题目前还 ...

  7. FileUpload控件

    FileUpload控件 属性:FileName: 获取上传的文件名 HasFile: 是否选择(存在)上传的文件 ContentLength: 获得上窜文件的大小,单位是字节(byte) 方法:Se ...

  8. Scala基础入门-3

    学习Scala——映射和元组 映射和和元组,也就是Maps和Tuples.Map这东西应该都挺明白的,就是键值对的集合.而元组,tuple,这东西并不是每个语言都有(Python中是有的,不过当时学的 ...

  9. Python学习笔记--Python字符串连接方法总结

    声明: 这些总结的学习笔记,一部分是自己在工作学习中总结,一部分是收集网络中的知识点总结而成的,但不到原文链接.如果有侵权,请知会,多谢. python中有很多字符串连接方式,总结一下: 1)最原始的 ...

  10. windows程序设计读书笔记3——字符显示2

    由于显示的字符可能会不全,我们很容易想到的一个解决办法是使用滚动条. 先看一下代码,再进行分析: /*------------------------------------------------- ...