【Gym - 102174】旅行的意义 (概率,DP)

本文介绍了一种解决DAG中从特定起点出发,遍历图的期望天数问题的算法。通过逆向思维,定义dp数组来计算从任意节点出发直至无法前进的总期望天数,考虑了节点停留和边的转移概率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Gym - 102174
题意:
给定一个DAG,起点在 1 1 1号,经过每个节点会停留一天,之后第二天等概率的选择继续停留一天,或者走向后继节点。但每个节点最多停留两天,经过每条边会花费一天。走到不能走为止,求期望天数。

反向逆推答案,定义 d p [ i ] dp[i] dp[i]表示以 i i i号点为起点走到不能走为止的期望天数, o u t [ i ] out[i] out[i]表示第 i i i个点的出度。
初始化: d p [ i ] = 1 + 1 + 1 o u t [ i ] + 1 dp[i]=1+1+\frac{1}{out[i]+1} dp[i]=1+1+out[i]+11 (到达第 i i i节点必定会在路上花费一天,到达后必定停留一天,又有 1 o u t [ i ] + 1 \frac{1}{out[i]+1} out[i]+11的停留一天。注意当 i = 1 i=1 i=1的时候,不必花费路上的一天,因为 1 1 1号点是起点)
转移: d p [ i ] + = ∑ d p [ j ] o u t [ i ] dp[i]+=\sum\frac{dp[j]}{out[i]} dp[i]+=out[i]dp[j] 。由于花完初始化的天数后,会等可能地( 1 o u t [ i ] \frac{1}{out[i]} out[i]1)选择其中一个后继节点并转移过来,所以每一个节点地期望为 d p [ j ] o u t [ i ] \frac{dp[j]}{out[i]} out[i]dp[j],再累和即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define LL long long
#define inl inline
#define re register
#define MAXN 101000
const LL mod=998244353ll;
using namespace std;
int n,m;
struct edge
{
	int to;
	edge* next;
}head[101000],stac[MAXN<<1];
int ind;
edge& gets(){return stac[++ind];}
void add(int from,int to)
{
	edge *p=&gets();
	p->to=to;
	p->next=head[from].next;
	head[from].next=p;
}
LL dp[MAXN],du[MAXN];
LL qpow(LL a,LL b)
{
	LL ans=1;
	for(;b;b>>=1,a=a*a%mod)if(b&1)ans=a*ans%mod;
	return ans;
}
bool vis[MAXN];
LL inv(LL i){return qpow(i,mod-2);}
void dfs(int i)
{
	vis[i]=1;
	dp[i]=(2+inv(du[i]+1))%mod;
	if(i==1)dp[i]--,dp[i]%=mod;
	for(edge *p=head[i].next;p!=NULL;p=p->next)
	{
		if(!vis[p->to])dfs(p->to); 
		dp[i]=(dp[i]+dp[p->to]*inv(du[i]))%mod;
	}
}
int main()
{
	int T;cin>>T;
	while(T--)
	{
		ind=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)head[i].next=NULL,vis[i]=dp[i]=du[i]=0;
		for(int s,v,i=1;i<=m;i++)
		{
			scanf("%d%d",&s,&v);
			du[s]++;add(s,v);
		}
		dfs(1);
		printf("%lld\n",(dp[1]%mod+mod)%mod);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值