解题思路
题意:每对折射关系,可以无限次折射给其他人,只要当前这个人受到伤害。
设a[i]表示i受到的初始伤害,f[i]表示i受到的总伤害(初始伤害+被别人折射过来的伤害,不减去自己折射出去的),p[i]表示i折射出去的比例和。则显然,i最终受到的伤害为f[i]*(1-p[i]):
p[i]p[i]p[i]可以在读入的时候直接处理出来,所以现在要求的是f[i]f[i]f[i]。我们设c[i][j]c[i][j]c[i][j]表示iii对jjj的伤害率,则:
- f[i]=a[i]+f[i]=a[i]+f[i]=a[i]+∑j!=if[j]∗c[j][i]\sum_{j!=i}f[j]*c[j][i]∑j!=if[j]∗c[j][i]
a[i],c[j][i]都已知,f[i]是未知数,则把式子移项得:
- ∑j!=if[j]∗c[j][i]−f[i]=−a[i]\sum_{j!=i}f[j]*c[j][i]-f[i]=-a[i]∑j!=if[j]∗c[j][i]−f[i]=−a[i]
这样的式子有n个,每个式子的未知数都是n个,且都是我们要求的,所以解出所有的方程就行了——高斯消元模板。
(其中f[i]f[i]f[i]的系数为−1-1−1,注意a[i]a[i]a[i]符号应该是负的,但是初值给的是正的所以最后要取absabsabs)
代码
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cmath>
using namespace std;
int n,m,x,y;
double a[210],c[210][210],p[210],z;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf",&a[i]);
c[i][n+1]=a[i];
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%lf",&x,&y,&z);
c[y][x]+=z;
p[x]+=z;
}
for(int i=1;i<=n;i++)
c[i][i]=-1;
for(int i=1;i<=n;i++)
{
int maxn=i;
for(int j=i+1;j<=n;j++)
{
if(abs(c[j][i])>abs(c[maxn][i]))
maxn=j;
}
for(int j=1;j<=n+1;j++)
swap(c[i][j],c[maxn][j]);
for(int j=1;j<=n;j++)
{
if(i!=j)
{
double tmp=c[j][i]/c[i][i];
for(int t=1;t<=n+1;t++)
c[j][t]-=c[i][t]*tmp;
}
}
}
for(int i=1;i<=n;i++)
printf("%.6lf\n",abs(c[i][n+1]/c[i][i]*(1-p[i])));
}