这道题的精度卡的人难受死了。
按照老师思路做的,矩阵的值表示i走到j的概率,求不经过某点的概率。
起始位置每个点的概率是1/N,然后将那个点外出的边都去掉,矩阵N次后,即可得到走到该点的概率,1-P即可。
注意:这道题有精度问题,可能会过小出现负数,1e-6
在构图的时候为了避免每次N循环,可以将每条边的连接顺序放入容器vector中,.size()就都有了。
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <bitset>
#include <iostream>
#include <algorithm>
#define inf 0x3fffffff
#define mid ((l+r)>>1)
const int maxn=100000+100;
typedef unsigned __int64 ull;
using namespace std;
int N,M,D;
double A[55][55],B[55][55],C[55][55];
double X[55][55];
int G[55][55];
double tt[2][55];
void matrix(double (*a)[55],double (*b)[55],double (*c)[55])
{
int i,j,k;
for(i=0;i<N;i++)
for(j=0;j<N;j++)
{
c[i][j]=0;
for(k=0;k<N;k++)
c[i][j]+=a[i][k]*b[k][j];
}
}
void qmaxtrix(int d)
{
int i,j,k;
memset(C,0,sizeof(C));
for(i=0;i<N;i++)
C[i][i]=1;
while(d)
{
if(d&1)
matrix(C,A,B),memcpy(C,B,sizeof(B));
matrix(A,A,B),memcpy(A,B,sizeof(B));
d>>=1;
}
}
int main()
{
int T;
int n,m,cas=1;
int i,j,k;
double ans;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&N,&M,&D);
memset(G,0,sizeof(G));
memset(X,0,sizeof(A));
for(i=0;i<M;i++)
scanf("%d%d",&n,&m),G[n-1][m-1]=G[m-1][n-1]=1;
double tmp=0;
for(i=0;i<N;i++)
{
tmp=0;
for(j=0;j<N;j++)
if(G[i][j])
tmp++;
if(tmp<1e-8) continue;
tmp=1/tmp;
for(j=0;j<N;j++)
if(G[i][j]) X[i][j]=tmp;
}
for(i=0;i<N;i++)
{
memcpy(A,X,sizeof(A));
for(j=0;j<N;j++)
A[i][j]=0;
A[i][i]=1;
qmaxtrix(D);
ans=1;
for(j=0;j<N;j++)
ans-=(1.0/N)*C[j][i];
if(ans<0) ans+=1e-6;
printf("%.10lf\n",ans);
}
}
return 0;
}
老师版本,构图不一样。
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<memory.h>
#include<vector>
#include<math.h>
using namespace std;
#define MAX 55
vector< vector<int> > edge;
int n, m, d;
double p[MAX][MAX];
#define E 1e-6
double CalRes(int k)
{
int st;
double val = 1.0;
for(st = 0; st < n; st++)
{
val -= 1.0 / n * p[st][k];
}
if(val < 0)
{
val += E;
}
return val;
}
double A[MAX][MAX];
double B[MAX][MAX];
double C[MAX][MAX];
void Mul()
{
int i, j, k;
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
C[i][j] = 0.0;
for(k = 0; k < n; k++)
{
C[i][j] += A[i][k] * B[k][j];
}
}
}
}
void CalPowA()
{
double res[MAX][MAX];
double D[MAX][MAX];
int i;
memset(res, 0, sizeof(res));
for(i = 0; i < n; i++)
{
res[i][i] = 1.0;
}
memcpy(D, p, sizeof(p));
int step = d;
while(step)
{
if(step % 2)
{
memcpy(A, res, sizeof(res));
memcpy(B, D, sizeof(D));
Mul();
memcpy(res, C, sizeof(C));
}
memcpy(A, D, sizeof(D));
memcpy(B, D, sizeof(D));
Mul();
memcpy(D, C, sizeof(C));
step /= 2;
}
memcpy(p, res, sizeof(res));
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "rt", stdin);
freopen("out.txt", "wt", stdout);
#endif
int T;
cin>>T;
int i, j, a, b;
for(; T; T--)
{
cin>>n>>m>>d;
edge.clear();
edge.resize(n);
for(i = 0; i < m; i++)
{
cin>>a>>b;
a--;
b--;
edge[a].push_back(b);
edge[b].push_back(a);
}
int k;
for(k = 0; k < n; k++)
{
memset(p, 0, sizeof(p));
for(i = 0; i < n; i++)
{
for(j = 0; j < edge[i].size(); j++)
{
p[i][edge[i][j]] = 1.0 / edge[i].size();
}
}
for(i = 0; i < n; i++)
{
p[k][i] = 0;
}
p[k][k] = 1.0;
CalPowA();
printf("%.10lf\n", CalRes(k));
}
}
return 0;
}
或者动态规划,每步是一个状态,这样dp[i][j] 表示走了i步走到j的概率。在计算的时候每走到这次计算的I的时候就停下.
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define INF 1000000000
//typedef __int64 LL;
#define N 10005
int t, n, d, m;
double dp[N][52];
vector<int > save[55];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%d", &t);
while(t--) {
scanf("%d%d%d", &n, &m, &d);
for(int i = 0; i <= n; i++) save[i].clear();
int u, v;
for(int i = 1; i <= m; i++) {
scanf("%d%d", &u, &v);
save[u].push_back(v);
save[v].push_back(u);
}
for(int i = 1; i <= n; i++) {
memset(dp, 0, sizeof(dp));
for(int j = 1; j <= n; j++) dp[0][j] = 1.0 / n;
for(int id = 1; id <= d; id ++) {
for(int j = 1; j <= n; j++) {
if(j == i) continue;
int ddd = save[j].size();
for(int kk = 0; kk < ddd; kk++) {
int k = save[j][kk];
dp[id][k] += 1.0 * dp[id - 1][j] / ddd ;
}
}
}
double ans = 0;
for(int j = 1; j <= n; j++) {
if(j == i) continue;
ans += dp[d][j];
}
printf("%lf\n", ans);
}
}
return 0;
}