题目大意
今天DZY 想要玩一个古老的游戏。他在一个有n 个房间并有m 个走廊互相连接的大迷宫里(每个走廊都允许双向通行)。你可以认为所有房间都被走廊直接或间接连接。
DZY 在迷宫里迷路了。现在他在第一房间并且有k 条命。他将会按如下所述行动:
首先,他会随机抽取一条从他现在所处房间出发的走廊。每个抽取范围内的走廊选中的机率相等。
然后他会沿着走廊走到走廊的另一端,并且回到第一步重复这个过程。
迷宫中的一些房间里面埋着陷阱。第一房间明显没有陷阱,第n 号房间明确地有一个陷阱。每次DZY 进入这些有陷阱的房间,他都会失去一条命。现在,DZY 知道如果他恰好有两条命时进入了第n 号房间,那么首先他会失去一条命,但是然后他会开启一个福利关卡。他想要知道他开启福利关卡的机率到底为多少。请帮助他。
解题思路
求出w[i][j]表示黑点(有陷阱的点)i到黑点j的概率,将白点连在一起考虑,可以很快算出w。接下来就可以用矩阵乘法求出解决问题。
code
#include
#include
#include
#include
#include
#define LD double
#define LL long long
#define ULL unsigned long long
#define min(a,b) ((a
#define max(a,b) ((a>b)?a:b)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define fr(i,j) for(int i=begin[j];i;i=next[i])
using namespace std;
int const mn=500+9,mm=2*1e5+9,inf=1e9;
int t,n,m,K,cnt,cnt2,gra,begin[509],to[mm],next[mm],num[1009],
map[509][509],du[1009],a[509];
LD w[109][109],ans[109][109],tmp[109][109];
void insert(int u,int v){
to[++gra]=v;
next[gra]=begin[u];
begin[u]=gra;
}
void dfs(int now,int bel){
num[now]=bel;
fr(i,now)if((!num[to[i]])&&(!a[to[i]]))dfs(to[i],bel);
}
void multiansw(){
fo(i,1,cnt2)fo(j,1,cnt2)tmp[i][j]=0;
fo(i,1,cnt2)fo(k,1,cnt2)fo(j,1,cnt2)tmp[i][k]+=ans[i][j]*w[j][k];
fo(i,1,cnt2)fo(j,1,cnt2)ans[i][j]=tmp[i][j];
}
void multiww(){
fo(i,1,cnt2)fo(j,1,cnt2)tmp[i][j]=0;
fo(i,1,cnt2)fo(k,1,cnt2)fo(j,1,cnt2)tmp[i][k]+=w[i][j]*w[j][k];
fo(i,1,cnt2)fo(j,1,cnt2)w[i][j]=tmp[i][j];
}
int main(){
freopen("games.in","r",stdin);
freopen("games.out","w",stdout);
scanf("%d%d%d",&n,&m,&K);K-=2;
fo(i,1,n)scanf("%d",&a[i]);
int u,v;
fo(i,1,m){
scanf("%d%d",&u,&v);
insert(u,v);
insert(v,u);
}
cnt=n,cnt2=0;
fo(i,1,n)if(!a[i]){
if(!num[i])cnt++,dfs(i,cnt);
}else num[i]=++cnt2;
fo(i,1,n)if(a[i])fr(j,i){
du[i]++;
if(!a[to[j]])du[num[to[j]]]++,map[i][num[to[j]]-n]++;
}
fo(i,1,n)if(a[i]){
fr(j,i)if(a[to[j]])w[num[i]][num[to[j]]]+=1.0/du[i];
fo(j,1,n)if(a[j])fo(k,1,cnt-n)
w[num[i]][num[j]]+=1.0*map[i][k]/du[i]*map[j][k]/du[k+n];
}
fo(i,1,n)if(a[i]&&map[i][num[1]]-n)
ans[1][num[i]]=1.0*map[i][num[1]-n]/du[num[1]];
while(K){
if(K&1)multiansw();
multiww();
K>>=1;
}
printf("%lf\n",ans[1][num[n]]);
return 0;
}