HDU 5001 Walk 概率DP BFS 矩阵递推 暴力
来源:互联网 发布:网络流行歌曲大全 对唱 编辑:程序博客网 时间:2024/04/30 05:55
题意:给出一张图,图上有N个点。开始时,等概率的选取起点。之后对于某个点,会从和他相连的所有点中,等概率的选取其中的一个点,继续走。一共要走D步。问,对于每个点,有多大的概率,使路径不包含该点。
思路:可以算概率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;}
0 0
- HDU 5001 Walk 概率DP BFS 矩阵递推 暴力
- HDU 5001 Walk(暴力+概率DP)
- hdu 5001 walk (概率dp+矩阵)
- 【HDU 5001】Walk(矩阵快速幂+概率DP)
- hdu 5001 Walk(概率dp+搜索,矩阵快速幂)
- hdu 5001 Walk (概率dp)
- [概率dp] hdu 5001 Walk
- HDU - 5001 Walk(概率dp)
- hdu 5001 Walk ( 概率DP )
- hdu 5001 Walk 概率DP
- hdu 5001 Walk 【概率dp】
- HDU 5001 Walk (概率dp)
- HDU 5001 Walk(概率DP)
- [ACM] hdu 5001 Walk (概率DP)
- HDU 5001 Walk 概率DP入门!
- HDU 5001 Walk (概率DP)
- HDU Walk (概率DP)
- HDU 5001 Walk (暴力)
- 不平凡之路
- SQL语句 where,group by,having,order by执行顺序
- Linux内核 Documentation下的00-INDEX文档翻译
- android YUV转RGB
- 猴子分桃问题的解决方法
- HDU 5001 Walk 概率DP BFS 矩阵递推 暴力
- centos 6 下编译gcc4.8.3
- 一个回射服务器程序,采用reactor模型和epoll多路复用
- AFNetworking速成教程(全)
- Java中数据类型的默认值
- Struts2配置RESULT中TYPE的参数说明
- HDOJ 题目38 布线问题(最小生成树)
- struts2之Action配置的各项默认值、result配置的各种试图转发类型及为应用指定多个struts配置文件
- 网申入口总结--9.11update