Description
今天DZY 想要玩一个古老的游戏。他在一个有n 个房间并有m 个走廊互相连接的大迷宫里(每个走廊都允许双向通行)。你可以认为所有房间都被走廊直接或间接连接。
DZY 在迷宫里迷路了。现在他在第一房间并且有k 条命。他将会按如下所述行动:
•首先,他会随机抽取一条从他现在所处房间出发的走廊。每个抽取范围内的走廊选中的机率相等。
•然后他会沿着走廊走到走廊的另一端,并且回到第一步重复这个过程。
迷宫中的一些房间里面埋着陷阱。第一房间明显没有陷阱,第n 号房间明确地有一个陷阱。每次DZY 进入这些有陷阱的房间,他都会失去一条命。现在,DZY 知道如果他恰好有两条命时进入了第n 号房间,那么首先他会失去一条命,但是然后他会开启一个福利关卡。他想要知道他开启福利关卡的机率到底为多少。请帮助他。
Input
输入第一行包含三个整数n,m,k(2 <=n <=500; 1 <= m <=10^5; 2 <= k <= 10^9)。
第二行包含n 个整数,它们每个都是0 或者1。如果第i 个整数为1,那么第i号房间有陷阱,否则它没有陷阱。请注意,有陷阱的房间的数量不会超过101。
保证第一房间没有陷阱,第n 号房间有陷阱。
接下来m 行,每行包含两个整数ui,vi(1 <=ui,vi<=n; ui<>vi),意味着现在的这条走廊连接的两个房间是ui 和vi。保证输入的这个走廊系统是连通的。
Output
输出唯一一个实数——DZY 开启福利关卡的机率。你的答案当它与标准答案的相对或绝对误差不超过10^-4 时被认为是正确的。
Sample Input
输入1:
5 5 3
0 0 1 0 1
1 2
2 3
3 4
4 5
1 2
输入2:
3 2 2
0 1 1
1 2
2 3
输入3:
2 1 3
0 1
1 2
Sample Output
输出1:
0.25000000
输出2:
-0.00000000
输出3:
1.00000000
Data Constraint
对于30% 的数据,n <=10
对于100%的数据,2 <=n <=500; 1 <= m <=10^5; 2 <= k <= 10^9
一开始其实一眼就看出来是高斯消元,模型是比较明显的。
一开始觉得直接dp,然后列公式,可以把式子移项一下,但是发现会n^4,然后就GG了,不知道该咋做,还有个k<=10^9。。感觉是矩阵乘法乱搞一下。
然后比赛就弃了这题。。
分析:。。为什么可以用高斯消元做呢。。首先我们要知道用高斯消元求解什么东西。
求解一个w(u,v)表示从房间u到房间v,经过的所有房间都无陷阱的概率,不包括u,v。
这个明显很简单,但是对于每个u,明显时间复杂度就是高斯消元n^3*n..这会炸。
但是我们通过仔细的思考可以发现,方程组的变量是不变的,只要每次重新计算常数项,就能做到n^3的时间复杂度,然后直接对着w跑矩阵乘法,跑k-2次,然后答案就是就是所有w相乘。
具体细节看代码。
#include
#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int n,m;
const int N=605;
typedef double matrix[N][N];
int k,flag[N],bz[N],cnt,d[N],e[N][N];
double w[N][N],w1[N<<1][N<<1],ans;
inline void gauss_elimination()
{
memset(w1,0,sizeof(w1));//w1是辅助数组,表示从i到j经过路径绝对没有陷阱的概率(包括i,j,这个和w不同)
fo(i,1,n)
{
w1[i][i]=1.0;
w1[i][i+n]=1.0;
fo(j,1,n)
if (!flag[j]&&j!=i)w1[i][j]=-e[i][j]/(double)d[j];//去掉陷阱,直接在前面搞个负号,到时候会自己减。
}
fo(i,1,n)//高斯消元
{
double now=w1[i][i];
fo(j,1,2*n)w1[i][j]/=now;
fo(j,1,n)
if (j!=i)
{
double tmp=w1[j][i];
fo(k,1,2*n)w1[j][k]-=tmp*w1[i][k];
}
}
fo(i,1,cnt)
fo(j,1,cnt)
fo(k,1,n)
w[j][i]+=w1[bz[i]][k+n]*(e[k][bz[j]]/(double)d[bz[j]]);
}
inline void mul(matrix &a,matrix b)
{
static matrix c;
memset(c,0,sizeof(c));
fo(k,1,cnt)
fo(i,1,cnt)
fo(j,1,cnt)c[i][j]+=a[i][k]*b[k][j];
memcpy(a,c,sizeof(a));
}
inline void pow(matrix a,int b)
{
static matrix r,base;
memcpy(base,a,sizeof(base));
fo(i,1,cnt)r[i][i]=1;
while (b)
{
if (b&1)mul(r,base);
mul(base,base);
b>>=1;
}
memcpy(w,r,sizeof(w));
}
int main()
{
freopen("games.in","r",stdin);
freopen("games.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
fo(i,1,n)
{
scanf("%d",&flag[i]);
if (flag[i])bz[++cnt]=i;
}
fo(i,1,m)
{
int x,y;
scanf("%d%d",&x,&y);
d[x]++,d[y]++;
e[x][y]++,e[y][x]++;
}
gauss_elimination();
k-=2;
pow(w,k);
fo(i,1,cnt)ans+=w1[bz[i]][1+n]*w[i][cnt];
printf("%.10lf\n",ans);
return 0;
}