题目链接: sdutoj 1129 电路稳定性
/*
【题目描述】
Heinz有一个电路,电路上有n个元件。已知元件i损坏而断开的概率是Pi(i=1,2,...,n,0≤pi≤1)。请你帮Heinz算出整个电路断路的概率。
元件的连接方式很简单,对电路的表示如下:
(1)一个元件是最小的电路,用A表示元件1,B表示元件2,如此类推。
(2)k个电路组成的串联电路表示为电路1,电路2,......,电路k。注串联电路用“,”号隔开。
(3)k个电路组成的并联电路表示为(电路1)(电路2)......(电路k)。注并联电路用“( )”标示。
对于两个电阻,如果它们断开的概率是P(i)和P(j)时,有:
(1)如果它们是并联电路,则断开的概率是P(i)*P(j)。
(2)如果它们是串联电路,则断开的概率是P(i)+(1-P(i))*P(j)。
【输入】
第1行是一个整数n(2≤n≤26),表示一共有多少个元件;
第2行是表示电路的字符串;
最后是n行,每行是一个实数Pi(i=1,2,...,n,0≤pi≤1),表示该元件断路的概率。
【输出】
输出一个实数,表示整个电路断路的概率,精确到小数点后4位。
【示例输入】
5
(A,B)((C)(D),E)
0.2
0.3
0.4
0.5
0.6
【示例输出】
把电路字符串先变成中缀表达式的形式,再变成后缀表达式,然后求值
0.2992
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <stack>
using namespace std;
double p[27]; //每个元件断路的概率
double BingLian(double x, double y); //并联概率
double ChuanLian(double x, double y); //串联概率
int main()
{
stack<char> circuit; //电路栈
stack<double> GaiLv; //求概率
int n; //n个元件
char strCircuit[105]; //电路字符串
char strZhongZhui[205]; //中缀表达式
char strHouZhui[205]; //后缀表达式
double total; //电路断路的概率
int len; //中缀和后缀表达式的长度
int i,j;
//输入
scanf("%d", &n);
cin >> strCircuit;
for (int i=1; i<=n; i++)
{
cin >> p[i];
}
//转换成中缀表达式,把逗号变加号,这样的括号 ')(' 变成 ')*('
j = strlen(strCircuit);
len = 0;
for (i=0; i<j; i++)
{
if ((i+1<j) && strCircuit[i] == ')' && strCircuit[i+1] == '(')
{
strZhongZhui[len++] = strCircuit[i];
strZhongZhui[len++] = '*';
}
else
{
if (strCircuit[i] == ',')
{
strZhongZhui[len++] = '+';
}
else
{
strZhongZhui[len++] = strCircuit[i];
}
}
}
strZhongZhui[len] = '\0';
//printf("%s\n", strZhongZhui);
//中缀转成后缀表达式,好计算
for (i=0, j=0; i<len; i++)
{
if (strZhongZhui[i] == '(') //左括号直接进栈
{
circuit.push('(');
}
//字符直接进后缀表达式数组中
else if ((strZhongZhui[i] >= 'A') && (strZhongZhui[i] <= 'Z'))
{
strHouZhui[j++] = strZhongZhui[i];
}
//右括号从栈中取操作符存入后缀表达式,直到遇到左括号
else if (strZhongZhui[i] == ')')
{
while (circuit.top() != '(')
{
strHouZhui[j++] = circuit.top();
circuit.pop();
}
circuit.pop();
}
//操作符优先级比栈顶高的直接进栈,如果优先级<=栈顶元素,就把栈顶元素存入后缀表达式
//直到栈顶元素的优先级低于操作符,则此操作符入栈,
else
{
if (strZhongZhui[i] == '+' && circuit.empty())
{
circuit.push('+');
}
else if (strZhongZhui[i] == '+')
{
while (circuit.top() != '(')
{
strHouZhui[j++] = circuit.top();
circuit.pop();
}
circuit.push('+');
}
else if (strZhongZhui[i] == '*' && circuit.empty())
{
circuit.push('*');
}
else
{
while (circuit.top() == '*')
{
strHouZhui[j++] = '*';
circuit.pop();
}
circuit.push('*');
}
}
}
while (!circuit.empty())
{
strHouZhui[j++] = circuit.top();
circuit.pop();
}
strHouZhui[j] = '\0';
//printf("%s", strHouZhui);
//计算后缀表达式,就是把字符转换成概率
for (i=0; i<j; i++)
{
if ((strHouZhui[i] >= 'A') && (strHouZhui[i] <= 'Z'))
{
GaiLv.push(p[strHouZhui[i]-'A' + 1]);
}
else
{
if (strHouZhui[i] == '+') //加号代表串联
{
double first = GaiLv.top(); //栈第一个值
GaiLv.pop();
double second = GaiLv.top(); //栈第二个值
total = ChuanLian(first, second); //求出这两个元件串联的概率
GaiLv.top() = total; //修改栈顶值
}
else //并联,原理和串联一样
{
double first = GaiLv.top();
GaiLv.pop();
double second = GaiLv.top();
total = BingLian(first, second);
GaiLv.top() = total;
}
}
}
total = GaiLv.top();
printf("%.4lf\n", total);
return 0;
}
//并联概率
double BingLian(double x, double y)
{
return x*y;
}
//串联概率
double ChuanLian(double x, double y)
{
return x+(1.0-x)*y;
}