题目链接
2 5 10 100 1 2 2 3 3 4 4 5 1 5 2 4 3 5 2 5 1 4 1 3 10 10 10 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 4 9
0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.6993317967 0.5864284952 0.4440860821 0.2275896991 0.4294074591 0.4851048742 0.4896018842 0.4525044250 0.3406567483 0.6421630037
题意:给一个n个点,m条边的双向联通图,旅行者要旅行d 天,旅行者随机选择起点,也就是说每个点选择的概率相等。旅行者下一天会随机的去与当前点相邻的一个点(所谓相邻的点就是与该点有一条直接相连的边),求d天旅行者没有访问第K个点的概率。
题解:目标状态为d天后没有访问第K个点,用dp[ i ][ j ]表示第i天,旅行者在点j,前i-1天没有访问过点K,要到达目标状态的概率。转移为:
dp[ i ] [ j ]=sum( 1/b * dp[ w ][ j+1 ] )。b表示与点i相邻的点的个数,w为与点 i 相邻的点。我们可以用记忆化搜索的方式实现转移。这个方法可以过,但是理论复杂度偏高。
由于N只有50,正解是用矩阵实现转移。由状态转移方程,我们可以这样构造矩阵,假设图为这样时:
n=4,m=4,边如下:
1 2
2 3
3 4
2 4
构造矩阵A如下:
0 1 0 0
1/3 0 1/3 1/3
0 1/2 0 1/2
0 1/2 1/2 0
假设K等于3,构造初始矩阵B
1
1
0
1
设矩阵C为
dp [ 1 ] [ 1 ]
dp [ 1 ] [ 2 ]
dp [ 1 ] [ 3 ]
dp [ 1 ] [ 4 ]
那么C=B*(A)^d。
复杂度为:50*50^3*logd。
矩阵乘法的代码如下:
#include<stdio.h> #include<algorithm> #include<queue> #include<stack> #include<map> #include<set> #include<vector> #include<iostream> #include<string.h> #include<string> #include<math.h> #include<stdlib.h> #define inff 0x3fffffff #define eps 1e-8 #define nn 55 #define mod 1000000007 typedef long long LL; using namespace std; int n,m,d; struct node { int en,next; }E[nn*nn]; int p[nn],num; void init() { memset(p,-1,sizeof(p)); num=0; } void add(int st,int en) { E[num].en=en; E[num].next=p[st]; p[st]=num++; } struct Matrix { int l,r; double a[55][55]; void clear() { l=r=0; memset(a,0,sizeof(a)); } Matrix operator*(const Matrix &b) const { Matrix tem; tem.clear(); tem.l=l,tem.r=b.r; for(int i=1;i<=tem.l;i++) { for(int j=1;j<=tem.r;j++) { for(int k=1;k<=r;k++) tem.a[i][j]+=a[i][k]*b.a[k][j]; } } return tem; } }ma,ix,ans; Matrix operator^(Matrix b,int y) { Matrix tem; tem.clear(); tem.l=b.l,tem.r=b.r; for(int i=1;i<=tem.l;i++) { for(int j=1;j<=tem.r;j++) { if(i==j) tem.a[i][j]=1; } } while(y) { if(y%2) { tem=tem*b; } y/=2; b=b*b; } return tem; } int main() { int t,i,u,v,j,k,w; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&d); init(); for(i=1;i<=m;i++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } int bian; ma.clear(); ma.l=ma.r=n; for(i=1;i<=n;i++) { bian=0; for(j=p[i];j+1;j=E[j].next) { bian++; } for(j=p[i];j+1;j=E[j].next) { w=E[j].en; ma.a[i][w]=(1.0)/bian; } } for(i=1;i<=n;i++) { ix.clear(); ix.l=ix.r=n; for(j=1;j<=n;j++) { for(k=1;k<=n;k++) { if(j==i) ix.a[j][k]=0; else ix.a[j][k]=ma.a[j][k]; } } ans.clear(); ans.l=n,ans.r=1; for(j=1;j<=n;j++) { if(i==j) ans.a[j][1]=0; else ans.a[j][1]=(1.0/n); } ans=(ix^d)*ans; double re=0; for(j=1;j<=n;j++) re+=ans.a[j][1]; printf("%.8lf\n",re); } } return 0; }
#include<stdio.h> #include<algorithm> #include<queue> #include<stack> #include<map> #include<set> #include<vector> #include<iostream> #include<string.h> #include<string> #include<math.h> #include<stdlib.h> #define inff 0x3fffffff #define eps 1e-8 #define nn 55 #define mod 1000000007 typedef long long LL; using namespace std; int n,m,d; struct node { int en,next; }E[nn*nn]; int p[nn],num; void init() { memset(p,-1,sizeof(p)); num=0; } void add(int st,int en) { E[num].en=en; E[num].next=p[st]; p[st]=num++; } double dp[55][11000]; bool vis[55][11000]; int jin; double dfs(int id,int step) { if(id==jin) return 0; if(vis[id][step]) return dp[id][step]; if(step==d) return 1.0; vis[id][step]=true; int i,w; dp[id][step]=0; int bian=0; double ix=0; for(i=p[id];i+1;i=E[i].next) { w=E[i].en; ix+=dfs(w,step+1); bian++; } dp[id][step]=ix/bian; return dp[id][step]; } int main() { int t,i,u,v,j,k; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&d); init(); for(i=1;i<=m;i++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } double ans; for(i=1;i<=n;i++) { ans=0; for(j=1;j<=n;j++) { for(k=0;k<=d;k++) vis[j][k]=false; } jin=i; for(j=1;j<=n;j++) { ans+=(1.0/n)*dfs(j,0); } printf("%.8lf\n",ans); } } return 0; }