HDU 5001 Walk 概率DP BFS 矩阵递推 暴力
2014-09-14 01:06
495 查看
题意:给出一张图,图上有N个点。开始时,等概率的选取起点。之后对于某个点,会从和他相连的所有点中,等概率的选取其中的一个点,继续走。一共要走D步。问,对于每个点,有多大的概率,使路径不包含该点。
思路:可以算概率DP,也能算BFS吧。赛中想到了一个点,但是没有想到删点重新建图。
因为要求出每个点的概率,我们必须枚举每个点。对于该点,我们要求所有不到该点路径的概率。也就相当于,将该点从图上删除,其他节点到达的概率总和。
需要注意的是,虽然该点在图上被删除了(其实是不能被访问),但每个点的度都没有变,如果改变了,会导致计算错误。
状态转移就是对距离计数,直接看代码吧。
代码如下:
同样,我们也可以用BFS的方式写转移;
这个题也可以用矩阵来求;
首先可以求出每个点到其他点的概率。这样就组成了一个矩阵。
一个点不可达,等价于其他点到它和它到其他点的概率为0。所以,对于每次枚举不可达点,我们可以将对应的矩阵的某些元素的概率设为0.这样求D次矩阵快速幂,就得到了, 长度为D,除去点i,其他点到达的概率,这样,我们在对所有的情况求和即可。
代码如下:
思路:可以算概率DP,也能算BFS吧。赛中想到了一个点,但是没有想到删点重新建图。
因为要求出每个点的概率,我们必须枚举每个点。对于该点,我们要求所有不到该点路径的概率。也就相当于,将该点从图上删除,其他节点到达的概率总和。
需要注意的是,虽然该点在图上被删除了(其实是不能被访问),但每个点的度都没有变,如果改变了,会导致计算错误。
状态转移就是对距离计数,直接看代码吧。
代码如下:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int MAX = 6000; int T,N,M,D; int head[MAX]; int nxt[MAX]; int to[MAX]; int deg[MAX]; int tot; double dp[10010][55]; void init() { memset(head,-1,sizeof(head)); memset(deg,0,sizeof(deg)); tot = 0; } void addedge(int u, int v) { to[tot] = v; nxt[tot] = head[u]; head[u] = tot++; deg[u]++; to[tot] = u; nxt[tot] = head[v]; head[v] = tot++; deg[v]++; } int main(void) { //freopen("input.txt","r",stdin); //freopen("out.txt","w",stdout); int u,v; scanf("%d", &T); while(T--){ scanf("%d %d %d",&N,&M,&D); init(); for(int i = 0 ; i < M; ++i){ scanf("%d %d", &u,&v); addedge(u,v); } for(int i = 1; i <= N; ++i){ memset(dp,0.0,sizeof(dp)); for(int j = 1; j <= N; ++j) if(j != i) dp[0][j] = 1.0 / N; for(int d = 0; d < D; ++d){ for(int j = 1; j <= N; ++j) if(j != i) for(int v = head[j]; ~v; v = nxt[v]) dp[d+1][to[v]] += dp[d][j] * (1.0 / deg[j]); } double ans = 0.0; for(int j = 1; j <= N; ++j) if(j != i) ans += dp[D][j]; printf("%.10f\n",ans); } } return 0; }
同样,我们也可以用BFS的方式写转移;
#include <cstdio> #include <algorithm> #include <cstring> #include <utility> using namespace std; typedef pair<int,int> pii; const int MAX = 6000; int T,N,M,D; int head[MAX],nxt[MAX],to[MAX],deg[MAX]; int tot; double dp[10010][55]; bool vis[10010][55]; int front, tail; pii que[10010 * 55]; void init() { memset(head,-1,sizeof(head)); memset(deg,0,sizeof(deg)); tot = 0; } void addedge(int u, int v) { to[tot] = v; nxt[tot] = head[u]; head[u] = tot++; deg[u]++; to[tot] = u; nxt[tot] = head[v]; head[v] = tot++; deg[v]++; } int main(void) { //freopen("input.txt","r",stdin); //freopen("out.txt","w",stdout); int u,v; scanf("%d", &T); while(T--){ scanf("%d %d %d",&N,&M,&D); init(); for(int i = 0 ; i < M; ++i){ scanf("%d %d", &u,&v); addedge(u,v); } for(int i = 1; i <= N; ++i){ memset(dp,0.0,sizeof(dp)); memset(vis,false,sizeof(vis)); front = tail = 0; for(int j = 1; j <= N; ++j) if(j != i){ dp[0][j] = 1.0 / N; que[tail++] = pii(0,j); vis[0][j] = true; } while(front < tail){ pii tmp = que[front++]; int d = tmp.first, u = tmp.second; if(u == i) continue; if(d >= D) break; for(int v = head[u]; ~v; v = nxt[v]){ dp[d+1][to[v]] += dp[d][u] / deg[u]; if(!vis[d+1][to[v]]){ vis[d+1][to[v]] = true; que[tail++] = pii(d+1,to[v]); } } } double ans = 0.0; for(int j = 1; j <= N; ++j) if(j != i) ans += dp[D][j]; printf("%.10f\n",ans); } } return 0; }
这个题也可以用矩阵来求;
首先可以求出每个点到其他点的概率。这样就组成了一个矩阵。
一个点不可达,等价于其他点到它和它到其他点的概率为0。所以,对于每次枚举不可达点,我们可以将对应的矩阵的某些元素的概率设为0.这样求D次矩阵快速幂,就得到了, 长度为D,除去点i,其他点到达的概率,这样,我们在对所有的情况求和即可。
代码如下:
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> using namespace std; int a[55][55]; int deg[55]; double mat[55][55]; struct Matrix{ double mat[55][55]; int n, m; void init(int n, int m){ this->n = n; this->m = m; memset(mat, 0, sizeof(mat)); } Matrix operator * (const Matrix& B){ Matrix C; C.init(n, B.m); for(int i=0; i<n; i++){ for(int j=0; j<B.m; j++){ for(int k=0; k<m; k++){ C.mat[i][j] += mat[i][k] * B.mat[k][j]; } } } return C; } Matrix quick_pow(int x){ Matrix Base, ret; Base.init(n,m); ret.init(n,m); for(int i=0; i<n; i++){ for(int j=0; j<m; j++){ Base.mat[i][j]=mat[i][j]; if(i==j) ret.mat[i][j]=1; } } while(x){ if(x&1) ret=ret*Base; Base=Base*Base; x>>=1; } return ret; } void print(){ for(int i=0; i<n; i++){ for(int j=0; j<m; j++){ cout<<mat[i][j]<<" "; } cout<<endl; } } }; double b[55]; Matrix s; int main() { int t, n, m, d, x, y; scanf("%d",&t); while(t--){ scanf("%d%d%d",&n,&m,&d); memset(a,0,sizeof a); memset(deg,0,sizeof deg); memset(mat,0,sizeof mat); for(int i=0; i<m; i++){ scanf("%d%d",&x,&y); x--, y--; a[x][y]=a[y][x]=1; deg[x]++, deg[y]++; } for(int c=0; c<n; c++){ double sum=0; for(int i=0; i<n; i++){ for(int j=0; j<n; j++){ if(a[i][j]) mat[i][j]=1.0/(double)deg[j]; } } for(int i=0; i<n; i++){ mat[c][i]=mat[i][c]=0.0; } s.init(n,n); for(int j=0; j<n; j++){ for(int k=0; k<n; k++){ s.mat[j][k]=mat[j][k]; } } s=s.quick_pow(d); for(int i=0; i<n; i++){ if(i==c) continue; for(int j=0; j<n; j++){ if(j==i) b[j]=1.0/(double)n; else b[j]=0.0; } for(int j=0; j<n; j++){ for(int k=0; k<n; k++){ sum+=b[j]*s.mat[k][j]; } //puts(""); } } printf("%.10f\n",sum); } } return 0; }
相关文章推荐
- 【HDU 5001】Walk(矩阵快速幂+概率DP)
- HDU 5001 Walk(暴力+概率DP)
- HDU 5001 Walk (暴力、概率dp)
- hdu 5001 Walk 概率DP
- HDU 5001 Walk (概率dp)
- HDU 5001-Walk(概率dp)
- hdu 5001 Walk 【概率dp】
- HDU 5001 Walk 求从任意点出发任意走不经过某个点的概率 概率dp 2014 ACM/ICPC Asia Regional Anshan Online
- HDU-5001 Walk (概率DP)
- hdu 5001 Walk (概率dp)
- hdu 5001 Walk(概率dp+搜索,矩阵快速幂)
- hdu 5001 Walk 概率dp 2014 ACM/ICPC Asia Regional Anshan Online
- HDU 5001 Walk 概率DP
- HDU - 5001 Walk(概率dp)
- HDU 5001 Walk (概率DP)
- hdu 5001 walk 概率dp入门题
- hdu 5001 Walk ( 概率DP )
- [概率dp] hdu 5001 Walk
- [ACM] hdu 5001 Walk (概率DP)
- HDU 5001 Walk(概率DP)