题目描述
Description
在一个游戏中有n个英雄,初始时每个英雄受到数值为ai的伤害,每个英雄都有一个技能“折射”,即减少自己受到的伤害,并将这部分伤害分摊给其他人。对于每个折射关系,我们用数对(xi,yi,zi)来表示xi将自己受到伤害去掉zi的比例,将这些伤害转移给yi(xi,yi是整数,zi是实数)。
求出经过反复折射后最后每个英雄受到的实际总伤害。
Input
第一行一个正整数:n,表示有n个英雄,第二行n个整数Ai,依次表示每个英雄受到的初始伤害。第三行一个正整数m,表示有m对折射关系。接下来m行,每行三个数xi,yi,zi,表示xi将自己受到伤害去掉zi的比例,将这些伤害转移给yi。
Output
输出n行,第i行表示第i个英雄最后受到的实际总伤害。保留六位小数。
Sample Input
3
1 0 2
3
1 2 0.3000
1 2 0.2000
2 1 0.5000
Sample Output
0.666667
0.333333
2.000000
Data Constraint
20%
全员坑人
根据题意模拟,每次记录本轮能反弹的伤害,然后根据时间大概算一下能跑多少轮
100%
想到了的话就是sb题
设f(x),表示x总共接受+反弹的伤害(即每轮存储在x的可弹的伤害之和)
若有一条边x–>y,比率为z
则f(y)=f(x)*z+y的初始伤害
因为x每收到一点伤害都要反弹,所以y收到的来自x的总伤害就是f(x)*z
高斯消元即可
最后ans[x]=f(x)*(1-∑zi) (zi∈x的出边),即算出x接受的真正伤害
解法好评,但卡精度差评
code
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define abs(x) ((x)>0?(x):-(x))
#define E 0.00000001
#define C 1000
using namespace std;
long double a[201][202];
int id[201];
long double ans[201];
long double tot[201];
int n,m,i,j,k,l;
long double s;
void work()
{
fo(i,1,n)
{
fo(j,1,n)
if (abs(a[i][j])>E)
{
if (!id[j])
{
id[j]=i;
s=a[i][j];
fo(k,j,n+1)
a[i][k]/=s;
break;
}
else
{
s=a[i][j];
fo(k,j,n+1)
a[i][k]-=s*a[id[j]][k];
}
}
}
fd(i,n,1)
{
ans[i]=a[id[i]][n+1];
fo(j,1,i-1)
a[j][n+1]-=ans[i]*a[j][i];
}
}
int main()
{
// freopen("damage6.in","r",stdin);
// freopen("S8_4_2.in","r",stdin);
scanf("%d",&n);
fo(i,1,n)
{
scanf("%d",&j);
a[i][i]=1*C;
a[i][n+1]=j*C*C;
}
scanf("%d",&m);
fo(i,1,m)
{
scanf("%d%d%Lf",&j,&k,&s);
a[k][j]-=s*C;
tot[j]+=s;
}
work();
fo(i,1,n)
printf("%0.6Lf\n",ans[i]*(1-tot[i])/C);
}