【CF446D】DZY Loves Games 高斯消元+矩陣乘法
【CF446D】DZY Loves Games
題意:一張n個(gè)點(diǎn)m條邊的無(wú)向圖,其中某些點(diǎn)是黑點(diǎn),1號(hào)點(diǎn)一定不是黑點(diǎn),n號(hào)點(diǎn)一定是黑點(diǎn)。問(wèn)從1開(kāi)始走,每次隨機(jī)選擇一個(gè)相鄰的點(diǎn)走過(guò)去,經(jīng)過(guò)恰好k個(gè)黑點(diǎn)到達(dá)n的概率。
$n\le 500,m\le 500000,k\le 10^9$,黑點(diǎn)個(gè)數(shù)不超過(guò)100.
題解:一眼就知道是高斯消元和矩乘什么的。我們先預(yù)處理出f[i][j]表示從第i個(gè)黑點(diǎn)開(kāi)始走到的下一個(gè)黑點(diǎn)是j的概率。這個(gè)用高斯消元容易搞定。然后上矩乘即可。但是問(wèn)題在于如果這樣做的話我們要做n遍高斯消元。不過(guò)我們發(fā)現(xiàn)每次消元時(shí)左邊的系數(shù)矩陣都是不變的,所以我們可以將n個(gè)方程組放到一起消元,復(fù)雜度就變成$O(n^3+10^6\log k)$了。
#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
typedef double db;
int n,m,K,tot;
db f[510][610];
int dan[510],d[510],p[510],pa[100010],pb[100010];
struct M
{
db v[105][105];
M () {memset(v,0,sizeof(v));}
db * operator [] (const int &a) {return v[a];}
inline M operator * (const M &a) const
{
M b;
int i,j,k;
for(i=1;i<=tot;i++) for(j=1;j<=tot;j++) for(k=1;k<=tot;k++) b.v[i][j]+=v[i][k]*a.v[k][j];
return b;
}
}S,T;
inline void pm(int y)
{
while(y)
{
if(y&1) S=S*T;
T=T*T,y>>=1;
}
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
int main()
{
n=rd(),m=rd(),K=rd();
int i,j,k,a,b;
for(i=1;i<=n;i++)
{
dan[i]=rd();
if(dan[i]) dan[i]=++tot,p[tot]=i;
}
for(i=1;i<=m;i++) pa[i]=rd(),pb[i]=rd(),d[pa[i]]++,d[pb[i]]++;
for(i=1;i<=m;i++)
{
a=pa[i],b=pb[i];
if(!dan[a]) f[b][a]-=1.0/d[a];
else f[b][dan[a]+n]+=1.0/d[a];
if(!dan[b]) f[a][b]-=1.0/d[b];
else f[a][dan[b]+n]+=1.0/d[b];
}
f[1][n+tot+1]=1;
for(i=1;i<=n;i++) f[i][i]+=1;
for(i=1;i<=n;i++)
{
for(j=k=i;j<=n;j++) if(fabs(f[j][i])>fabs(f[k][i])) k=j;
if(i!=k) for(j=i;j<=n+tot+1;j++) swap(f[i][j],f[k][j]);
db tmp=f[i][i];
for(j=i;j<=n+tot+1;j++) f[i][j]/=tmp;
for(j=1;j<=n;j++) if(j!=i)
{
tmp=f[j][i];
for(k=1;k<=n+tot+1;k++) f[j][k]-=f[i][k]*tmp;
}
}
for(i=1;i<=tot;i++) for(j=1;j<=tot;j++) T[i][j]=f[p[j]][i+n];
for(i=1;i<=tot;i++) S[1][i]=f[p[i]][n+tot+1];
pm(K-2);
printf("%.10lf",S[1][tot]);
return 0;
}
| 歡迎來(lái)原網(wǎng)站坐坐! >原文鏈接<

浙公網(wǎng)安備 33010602011771號(hào)