【ybtoj】【期望问题】路径长度
题意
题解
乍一看:这也太简单了,纯纯的水题啊!
我原本的思路:\(dis_i\) 表示 \(1\) 到 \(i\) 的期望距离,转移大致是 \(dis_v+=(dis_v+1.0*w_i)/oud_v\).
后来发现不对:对于每一条路选择的概率要传递下去,于是又加上一个数组 \(p_i\) 表示走到 \(i\) 的概率。
但是无法转移,简单的样例就足以说明一切。
这种做法的问题在于无法求出一条完整路径的期望距离。
看了题解拓宽思路:
更改 \(dis_i\) 的定义,改为从 \(i\) 出发到 \(n\) 的路径期望长度,那么 \(dis_i=(\sum dis_j+w(i,j))/oud_i\)
同时反向建图跑拓扑,就可以避免这个问题。
同时贴上正确代码和错误代码,方便比较区别。
错误代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f,N = 1e5+10,M = N<<1;
inline ll read()
{
ll ret=0;char ch=' ',c=getchar();
while(!(c>='0'&&c<='9')) ch=c,c=getchar();
while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
return ch=='-'?-ret:ret;
}
int n,m;
int ecnt=-1,head[N],oud[N],ind[N];
double dis[N],p[N];
struct edge
{
int nxt,to,w;
}a[M];
inline void add(int x,int y,int w)
{
a[++ecnt]=(edge){head[x],y,w};
head[x]=ecnt;
}
queue<int> q;
void bfs()
{
q.push(1);p[1]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];~i;i=a[i].nxt)
{
int v=a[i].to;
p[v]+=p[u]/oud[u];
dis[v]+=dis[u]+1.0*a[i].w*p[v];
ind[v]--;
if(!ind[v]) q.push(v);
}
printf("u=%d,dis[%d]=%.2lf\n",u,u,dis[u]);
}
}
int main()
{
n=read(),m=read();
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++)
{
int u=read(),v=read(),w=read();
add(u,v,w);
oud[u]++,ind[v]++;
}
bfs();
printf("%.2lf",dis[n]);
return 0;
}
正确代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f,N = 1e5+10,M = N<<1;
inline ll read()
{
ll ret=0;char ch=' ',c=getchar();
while(!(c>='0'&&c<='9')) ch=c,c=getchar();
while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
return ch=='-'?-ret:ret;
}
int n,m;
int ecnt=-1,head[N],oud[N],ind[N];
double dis[N];
struct edge
{
int nxt,to,w;
}a[M];
inline void add(int x,int y,int w)
{
a[++ecnt]=(edge){head[x],y,w};
head[x]=ecnt;
}
queue<int> q;
void bfs()
{
q.push(n);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];~i;i=a[i].nxt)
{
int v=a[i].to;
dis[v]+=(dis[u]+1.0*a[i].w)/oud[v];
ind[v]--;
if(!ind[v]) q.push(v);
}
//printf("u=%d,dis[%d]=%.2lf\n",u,u,dis[u]);
}
}
int main()
{
n=read(),m=read();
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++)
{
int u=read(),v=read(),w=read();
add(v,u,w);
oud[u]++,ind[u]++;
}
bfs();
printf("%.2lf",dis[1]);
return 0;
}