问题描述
在软件或系统开发中,我们会遇到各种各样的故障,为了从故障现象反推故障原因,工程师们会总结一种叫做相关性矩阵的二维表格,来表示故障原因与故障现象之间的关系。比如:
其中每行表示一种故障原因,每一列表示一种故障现象。该矩阵表示故障原因A可能产生故障现象2,3,4,故障原因B可能产生故障现象1,3。在实际开发过程中,如果出现了故障原因,工程师就根据故障原因产生的概率,并按照概率大小对故障原因进行排查,以达到快速定位故障原因的目的。
现在,我们假设系统开发中同一时间只会出现一种故障原因,并且故障原因引起各故障现象是独立事件。举个例子来说:
假设系统现在发生了故障原因A,有1/3的概率出现故障现象2,有1/4的概率出现故障现象3,有1/2的概率出现故障现象4.由于3种现象是独立发生的,因此有1/2×3×4的概率同时出现故障2,3,4
约定若相关性矩阵中没有‘x' 记号,则表示该故障原因一定不会产生某故障现象,比如故障原因A,一定不会产生故障现象1.
根据历史经验数据,我们统计得到了每一种故障原因出现的概率以及每一种故障原因对应的故障现象产生概率
现在已知系统出现的故障现象,求问各个故障原因发生的概率
输入格式
第一行:2个正整数N,M。N表示故障原因的个数(编号1 ... N ), M 表示故障现象的个数(编号1 ...M)
第2行:N个整数,第i 个数表示故障原因 i 产生的概率 Pi。
第3 ... N +2行:每行M个整数,第 i+2行第 j 个整数Pij表示故障原因 i出现故障现象j 的概率(百分比)。
第N+3行:1个正整数K,表示目前出现的故障现象数量。
第N+4 行:K个正整数,依次为当前出现的故障现象编号,不会重复
输出格式
第1 ... N行:按概率从高到低输出每种故障原因及其可能的概率,若出现概率相同则优先输出编号小的故障原因。第1个数为故障原因编号,第2个数为故障概率(百分比),保留2位小数。
样例输入
3 5
30 20 50
0 50 33 25 0
30 0 35 0 0
0 0 0 25 60
1
3
样例输出
2 56.89
1 43.11
3 0.00
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
using namespace std;
int n,m; //n行,m列
int yuanyin[450];
int p1[450][450];
int k;
int guzhang[4500];
int vis2[450];
int vis1[450];
double dange[450];
int id[450];
bool cmp(int a,int b){
if(fabs(dange[a]-dange[b])>1e-8){
return dange[a]>dange[b];
}else{
return a<b;
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>yuanyin[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>p1[i][j];
}
}
cin>>k;
for(int i=1;i<=k;i++){
cin>>guzhang[i];
vis1[guzhang[i]]=1; //标记故障
}
double num=0;
for(int i=1;i<=n;i++){
dange[i]=1; //便于乘
for(int j=1;j<=m;j++){
if(vis1[j]){ //此点是故障点
dange[i]=(double)dange[i]*p1[i][j]/100.0;
}else{
dange[i]=(double)dange[i]*(100-p1[i][j])/100.0;
}
}
dange[i]=(double)dange[i]*yuanyin[i]/100.0;
num+=dange[i];
}
if(fabs(num)<1e-9){
for(int i = 1 ; i <= n ; i ++){
printf("%lld 0.00\n" , i) ;
}
return 0 ;
}
for(int i=1;i<=n;i++){
id[i]=i;
dange[i]=dange[i]*100.0/num;
}
sort(id+1,id+1+n,cmp); //根据dange的值排id
for(int i=1;i<=n;i++){
printf("%lld %0.2lf\n",id[i],dange[id[i]]);
}
return 0;
}