bzoj 1415 [Noi2005]聪聪和可可——其实无环的图上概率
Posted narh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1415 [Noi2005]聪聪和可可——其实无环的图上概率相关的知识,希望对你有一定的参考价值。
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1415
乍一看和“游走”一样。于是高斯消元。n^2状态,复杂度n^6……
看看TJ,发现因为聪聪不是随便走的,所以聪聪一直逼近可可。故其实无环。可以记搜。
(1A还是不错的)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=1005; int n,m,l0,l1,nxt[N][N],dfn[N],du[N]; double dp[N][N]; bool vis[N],vs[N][N]; priority_queue<int,vector<int>,greater<int> >ed[N]; void add(int x,int y) { ed[x].push(y);ed[y].push(x); du[x]++;du[y]++; } void bfs(int cr) { priority_queue<int,vector<int>,greater<int> >tp; memset(vis,0,sizeof vis);memset(dfn,0,sizeof dfn); queue<int> q;q.push(cr);vis[cr]=1;nxt[cr][cr]=cr; while(q.size()) { int k=q.front();q.pop(); tp=ed[k]; while(tp.size()) { int v=tp.top();tp.pop(); if(vis[v])continue; dfn[v]=dfn[k]+1;vis[v]=1;q.push(v); if(dfn[v]>2)nxt[v][cr]=nxt[k][cr]; else nxt[v][cr]=v; } } } double dfs(int x,int y)//coco->x ,cncn->y { // printf("x=%d y=%d ",x,y); if(vs[x][y])return dp[x][y];vs[x][y]=1; if(nxt[x][y]==x){/*printf("rt x=%d y=%d ",x,y);*/return dp[x][y]=1;} double ret=(dfs(x,nxt[x][y])+(nxt[x][y]!=x))/(du[x]+1); priority_queue<int,vector<int>,greater<int> >tp=ed[x];//每层定义 // printf("siz[%d]=%d ",x,tp.size()); while(tp.size()) { int v=tp.top();tp.pop(); // printf("v=%d nxt[%d][%d]=%d ",v,x,y,nxt[x][y]); ret+=(dfs(v,nxt[x][y])+(nxt[x][y]!=v))/(du[x]+1); } // printf("ret=%.3lf ",ret); return dp[x][y]=ret; } int main() { scanf("%d%d%d%d",&n,&m,&l0,&l1);int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y);add(x,y); } for(int i=1;i<=n;i++)bfs(i); printf("%.3lf",dfs(l1,l0)); return 0; }
看看TJ,发现判断得那么纠结是因为x==y时正常应返回0。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=1005; int n,m,l0,l1,nxt[N][N],dfn[N],du[N]; double dp[N][N]; bool vis[N],vs[N][N]; priority_queue<int,vector<int>,greater<int> >ed[N]; void add(int x,int y) { ed[x].push(y);ed[y].push(x); du[x]++;du[y]++; } void bfs(int cr) { priority_queue<int,vector<int>,greater<int> >tp; memset(vis,0,sizeof vis);memset(dfn,0,sizeof dfn); queue<int> q;q.push(cr);vis[cr]=1;nxt[cr][cr]=cr; while(q.size()) { int k=q.front();q.pop(); tp=ed[k]; while(tp.size()) { int v=tp.top();tp.pop(); if(vis[v])continue; dfn[v]=dfn[k]+1;vis[v]=1;q.push(v); if(dfn[v]>2)nxt[v][cr]=nxt[k][cr]; else nxt[v][cr]=v; } } } double dfs(int x,int y)//coco->x ,cncn->y { if(vs[x][y])return dp[x][y];vs[x][y]=1; if(x==y)return dp[x][y]=0;// if(nxt[x][y]==x)return dp[x][y]=1; double ret=dfs(x,nxt[x][y])/(du[x]+1)+1; priority_queue<int,vector<int>,greater<int> >tp=ed[x];//每层定义 while(tp.size()) { int v=tp.top();tp.pop(); ret+=dfs(v,nxt[x][y])/(du[x]+1); } return dp[x][y]=ret; } int main() { scanf("%d%d%d%d",&n,&m,&l0,&l1);int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y);add(x,y); } for(int i=1;i<=n;i++)bfs(i); printf("%.3lf",dfs(l1,l0)); return 0; }
但是自己代码巨慢……想来是用了优先队列的缘故(为了标号字典序)。尝试改一改。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=1005; int n,m,l0,l1,nxt[N][N],dfn[N],du[N],head[N],xnt; double dp[N][N]; bool vis[N],vs[N][N]; priority_queue<int,vector<int>,greater<int> >ed[N]; struct Edge{ int next,to; Edge(int n=0,int t=0):next(n),to(t) {} }edge[N<<1]; void add(int x,int y) { edge[++xnt]=Edge(head[x],y);head[x]=xnt; edge[++xnt]=Edge(head[y],x);head[y]=xnt; ed[x].push(y);ed[y].push(x); du[x]++;du[y]++; } void bfs(int cr) { priority_queue<int,vector<int>,greater<int> >tp; memset(vis,0,sizeof vis);memset(dfn,0,sizeof dfn); queue<int> q;q.push(cr);vis[cr]=1;nxt[cr][cr]=cr; while(q.size()) { int k=q.front();q.pop(); tp=ed[k]; while(tp.size()) { int v=tp.top();tp.pop(); if(vis[v])continue; dfn[v]=dfn[k]+1;vis[v]=1;q.push(v); if(dfn[v]>2)nxt[v][cr]=nxt[k][cr]; else nxt[v][cr]=v; } } } double dfs(int x,int y)//coco->x ,cncn->y { if(vs[x][y])return dp[x][y];vs[x][y]=1; if(x==y)return dp[x][y]=0;// if(nxt[x][y]==x)return dp[x][y]=1; double ret=dfs(x,nxt[x][y])/(du[x]+1)+1; for(int i=head[x];i;i=edge[i].next) ret+=dfs(edge[i].to,nxt[x][y])/(du[x]+1); return dp[x][y]=ret; } int main() { scanf("%d%d%d%d",&n,&m,&l0,&l1);int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y);add(x,y); } for(int i=1;i<=n;i++)bfs(i); printf("%.3lf",dfs(l1,l0)); return 0; }
结果只是快了28ms。
别人用一些方法保证字典序。
这个人bfs+两步保证dis最小的前提下调整标号至最小。https://blog.csdn.net/clove_unique/article/details/62237321
这个人spfa的同时判断标号。(但只能记录一步的pre)https://blog.csdn.net/PoPoQQQ/article/details/40896403(bfs因为是bfs所以不能边求dis边调整标号)
可是我都没记录dis。用的dfn。所以懒得改了……比较欣赏第一个人的写法。
以上是关于bzoj 1415 [Noi2005]聪聪和可可——其实无环的图上概率的主要内容,如果未能解决你的问题,请参考以下文章