3640: JC的小苹果
Time Limit: 15 Sec Memory Limit: 256 MBSubmit: 332 Solved: 120
[ Submit][ Status][ Discuss]
Description
让我们继续JC和DZY的故事。
“你是我的小丫小苹果,怎么爱你都不嫌多!”
“点亮我生命的火,火火火火火!”
话说JC历经艰辛来到了城市B,但是由于他的疏忽DZY偷走了他的小苹果!没有小苹果怎么听歌!他发现邪恶的DZY把他的小苹果藏在了一个迷宫里。JC在经历了之前的战斗后他还剩下hp点血。开始JC在1号点,他的小苹果在N号点。DZY在一些点里放了怪兽。当JC每次遇到位置在i的怪兽时他会损失Ai点血。当JC的血小于等于0时他就会被自动弹出迷宫并且再也无法进入。
但是JC迷路了,他每次只能从当前所在点出发等概率的选择一条道路走。所有道路都是双向的,一共有m条,怪兽无法被杀死。现在JC想知道他找到他的小苹果的概率。
P.S.大家都知道这个系列是提高组模拟赛,所以这是一道送分题balabala
Input
第一行三个整数表示n,m,hp。接下来一行整数,第i个表示jc到第i个点要损失的血量。保证第1个和n个数为0。接下来m行每行两个整数a,b表示ab间有一条无向边。
Output
仅一行,表示JC找到他的小苹果的期望概率,保留八位小数。
Sample Input
0 1 0
1 2
1 3
2 3
Sample Output
HINT
对于100%的数据 2<=n<=150,hp<=10000,m<=5000,保证图联通。
解题思路:首先因为血量可以为0,所以这不是个DAG(可直接递推)。
那么就要考虑形成环了,那么可以用高斯消元处理,但是,如果每次
都一次高斯消元的话,会超时,那么可以想到,每次高斯消元的系数
都是不变的,就是说,原来的f[n][n+1],我们把它开一个数组,表示
y[i][j]表示,由j对i的贡献的系数,预处理以后,递推hp,每次就可以用
y数组的这个系数来更新f数组。最后统计答案。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,hp,len;
int to[11000],next[11000],h[11000];
int jc[200];
bool ch[200][200];
long double du[200],x[200][200],y[200][200],f[11000][200],zan[200];
inline int read()
{
char y; int x=0,f=1; y=getchar();
while(y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while(y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}
void insert(int x,int y)
{
++len; to[len]=y; next[len]=h[x]; h[x]=len;
}
void work()
{
for (int i=1;i<=n-1;++i)
{
int u=h[i];
while (u!=0)
{
if (jc[to[u]]==0)
{
x[to[u]][i]-=1/du[i];
}
u=next[u];
}
}
for (int i=1;i<=n;++i) x[i][i]+=1;
for (int i=1;i<=n;++i) y[i][i]=1;
for (int i=1;i<=n;++i)
{
long double ogg=x[i][i];
for (int j=1;j<=n;++j) y[i][j]/=ogg;
for (int j=i;j<=n;++j)
{
x[i][j]/=ogg;
}
for (int j=i+1;j<=n;++j)
{
ogg=x[j][i];
for (int k=1;k<=n;++k) y[j][k]-=ogg*y[i][k];
for (int k=i;k<=n;++k) x[j][k]-=ogg*x[i][k];
}
}
for (int i=n;i>=2;--i)
for (int j=i-1;j>=1;--j)
{
long double ogg=x[j][i];
for (int k=1;k<=n;++k) y[j][k]-=y[i][k]*ogg;
x[j][i]=0;
}
}
int main()
{
n=read(); m=read(); hp=read();
for (int i=1;i<=n;++i) jc[i]=read();
memset(ch,false,sizeof(ch));
for (int i=1;i<=m;++i)
{
int x,y; x=read(); y=read();
if (x!=y)insert(x,y),++du[x];
insert(y,x); ++du[y];
}
work();
f[hp][1]=1;
for (int i=hp;i>=1;--i)
{
memset(zan,0,sizeof(zan));
for (int j=1;j<=n;++j)
{
for (int k=1;k<=n;++k)
zan[j]+=f[i][k]*y[j][k];
}
for (int j=1;j<=n;++j) f[i][j]=zan[j];
for (int j=1;j<=n-1;++j)
{
int u=h[j];
while (u!=0)
{
if (jc[to[u]]!=0 && i-jc[to[u]]>0)
{
f[i-jc[to[u]]][to[u]]+=f[i][j]/du[j];
}
u=next[u];
}
}
}
long double ans=0;
for (int i=hp;i>=1;--i)
{
ans+=f[i][n];
}
printf("%.8Lf",ans);
}