poj 1487 Single-Player Games(高斯消元+字符串处理)

106 篇文章 0 订阅
64 篇文章 0 订阅

题意:

给你几棵树,每棵树的叶子节点都有一个值,这个值可能是直接给出,也可能是其它树的期望值,问每棵树走到叶子节点获得的值的期望是多少。

每棵树的编号是从a到a+n-1.

思路:

被这道题,卡了好几天,快卡哭了QAQ。

首先麻烦的是字符串的处理,用递归是一种比较好的办法,先记录下同一个括号里所存在的元素个数,再往下递归就好。

然后建立方程。记a树的期望为Ea,把有确定值的叶子节点的期望求出来加和为va,以及求出走到存放其它树(str)的期望的叶子节点的概率记为a[str-'a'],

则可列出方程:   Ea=Ea*a['a'-'a']+Eb*a['b'-'a']+Ec*a['c'-'a']……+va;

                          移项得:va=(1-Ea)*a['a'-'a']-Eb*a['b'-'a']-Ec*a['c'-'a']......(我的程序不这样移就会wa,不知道为什么)

然后每棵树都可以列出这样的一个方程,套用下高消消元浮点型解模板。

但是这个题还需要注意一个情况,当出现有自由变元的时候,并不是就有多解,对于一些只包含一个自由变元的方程组,是可以求解的,我们就要求出这些方程组中那个唯一的自由变元的解,而对于其它不能确定的变元,输出undefined即可。


这题真恶心!


代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=1e2;
const double eps=1e-8;
int n;
char str[maxn+5];
double a[maxn+5][maxn+5];
double b[maxn+5];
double kh[maxn+5];
bool v[maxn+5];
bool freex[maxn+5]; //记录是否为自由变元
struct eee
{
    int s;
    double p;
    int valu;
    int zt;
} que[maxn+5];
void gauss(int n)
{
    int i, j, row, col, equ=n, var=n;
    for(row=0, col=0; row<equ && col<var; row++, col++)
    {
        int maxr=row;
        for(i=row; i<equ; i++)
        {
            if(fabs(a[i][col])>fabs(a[maxr][col]))
            {
                maxr=i;
            }
        }
        if(fabs(a[maxr][col])<eps)
        {
            row--;
            continue;
        }
        for(j=col; j<var+1; j++)
        {
            swap(a[maxr][j], a[row][j]);
        }
        for(i=row+1; i<equ; i++)
        {
            if(fabs(a[i][col])>eps)
            {
                double s=a[i][col]/a[row][col];
                for(j=col; j<var+1; j++)
                {
                    a[i][j]-=a[row][j]*s;
                }
            }
        }
    }
    if(row < n)
    {
        for(i=row-1; i>=0; i--)
        {
            int num=0, id;
            for(j=i; j<n; j++) //找出该方程中有几个自由变元
            {
                if(freex[j] && fabs(a[i][j])>eps)
                {
                    num++;
                    id=j;  //当出现只有一个自由变元时,就是id了
                }
            }
            if(num>1)continue; // 有多个自由变元,该方程无解
            double tmp=a[i][n];
            for(j=id+1; j<n; j++)
            {
               tmp-=a[i][j]*b[j];
            }
            b[id]=tmp/a[i][id];
            freex[id]=0; //已求出该变元的值,将其标记为非自由变元。
        }
        for(i=0; i<n; i++)
        {
            printf("Expected score for %c ", i+'a');
            if(!freex[i])printf("= %.3lf\n", b[i]);
            else printf("undefined\n");
        }
//        printf("\n");
        return;
    }
    for(i=equ-1; i>=0; i--)
    {
        double tmp=a[i][var];
        for(j=i+1; j<var; j++)
        {
            tmp-=a[i][j]*b[j];
        }
//        printf("%.3lf %d %.3lf\n", a[i][i], i, tmp);
        b[i]=tmp/a[i][i];

    }
    for(i=0; i<n; i++)
    {
        printf("Expected score for %c = %.3lf\n", i+'a', b[i]);
    }

}

void find(int x, double p, int s, int d)
{
    int i, j;
    int num=0;// kuohao number
    double enumber=0.0; // element number
    for(i=s+1; i<d; i++)
    {
        if(str[i]=='(')
        {
            num++;
        }
        else if(str[i]==')')
        {
            num--;
            if(num==0)
            {
                enumber+=1;
            }
        }
        else if(str[i]!=' ' && num==0)
        {
            while(str[i+1]>='0' && str[i+1]<='9')i++;

            enumber+=1;
        }
    }
    num=0;
    int st=0;
    for(i=s+1; i<d; i++)
    {
        if(str[i]=='(')
        {
           if(num==0) st=i;
            num++;

        }
        else if(str[i]==')')
        {
            num--;
            if(num==0)
            {

                find(x, p*1.0/enumber, st, i);
            }
        }
        else if(str[i]>='a' && str[i]<='z' && num==0)
        {
            a[x][str[i]-'a']-=p*1.0/enumber;
        }
        else if(str[i]=='-' && num==0)
        {
            int ans=0;
            i++;
            while(str[i]>='0' && str[i]<='9')
            {
                ans=ans*10+str[i]-'0';

                i++;
            }
            ans=-ans;
            a[x][n]+=1.0*ans*p/enumber;
        }
        else if(str[i]<='9' && str[i]>='0' && num==0)
        {
            int ans=0;
            while(str[i]<='9' && str[i]>='0')
            {
                ans=ans*10+str[i]-'0';
                i++;
            }

//            printf("%lf %.0lf\n", ans*p/enumber, ans);
            a[x][n]+=1.0*ans*p/enumber;
        }
    }
    return;
}

int main()
{
    int isfirst=1;
    int e=1;
    while(~scanf("%d", &n))
    {
        if(n==0)break;

        int i, j;
        memset(v, 0, sizeof(v));
        memset(a, 0, sizeof(a));
        memset(freex, true, sizeof(freex)); //先将所有变量默认为自由变元,之后会在求解过程中求出哪些变元不是自由变元。
        getchar();
        for(i=0; i<n; i++)
        {

            gets(str);
//            printf("%s\n", str);
            double var=0;
            double p=1.0;
            a[i][i]=1;
            int st=0, ed=0, len=strlen(str);
            for(j=0; str[j]; j++)
            {
                if(str[j]=='(')
                {
                   st=j;break;
                }
            }
            for(j=len-1; j>=0; j--)if(str[j]==')'){ed=j;break;}
            find(i, p, st, ed);
        }

        if(isfirst)isfirst=0;
        else printf("\n");
        printf("Game %d\n", e++);
        gauss(n);

    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值