【2019ICPC南京网络赛】D. Robots

原题题址
说说实话,这题在没接触过概率dp的时候我不太会做,自学了点概率dp的时候就不太难了。说实话我的题意分析有问题,以为只需要算出期望日期就行了,结果忘了还要算期望花费。
其实两次期望dp就行,而且由于两个转移方式相同,推出一个就行了。
时间期望, d p 1 [ i ] dp_{1}[i] dp1[i]表示到点i的期望时间,根据每个点的概率回推,每次回推时间多1,很容易得到。
d p 1 [ i ] = d p 1 [ i ] N + ∑ v d p 1 [ v ] N + 1 dp_{1}[i] = \frac{dp_{1}[i]}{N}+\frac{\sum_{v}dp_{1}[v]}{N}+1 dp1[i]=Ndp1[i]+Nvdp1[v]+1
根据类推,每次回推的增加的部分改成每个点期望花费的价值(即是时间)
d p 2 [ i ] = d p 2 [ i ] N + ∑ v d p 2 [ v ] N + d p 1 [ i ] dp_{2}[i] = \frac{dp_{2}[i]}{N}+\frac{\sum_{v}dp_{2}[v]}{N}+dp_{1}[i] dp2[i]=Ndp2[i]+Nvdp2[v]+dp1[i]
直接上代码:

#include"iostream"
#include"cstdio"
#include"vector"
using namespace std;
const int maxn = 2e5+10;
vector<int> a[maxn];
double dp1[maxn],dp2[maxn];  
int P,E;
double Find1(int x){
	 if(dp1[x]>0||x == P)return dp1[x];
	 else{
	 	int L = a[x].size();
	 	double res = 0;
	 	for(int i = 0;i < L;i++)
			res+=((Find1(a[x][i])));
	    dp1[x] = (res+L+1)/(L);
	 }
	 return dp1[x];
}
double Find2(int x){
	 if(dp2[x]>0||x == P)return dp2[x];
	 else{
	 	int L = a[x].size();
	 	double res = 0;
	 	for(int i = 0;i < L;i++)
			res+=((Find2(a[x][i])));
	    dp2[x] = (res + dp1[x])/(L)+dp1[x];
	 }
	 return dp2[x];
}
int main(){
	int T;
	cin >> T;
	while(T--){
		
		scanf("%d%d",&P,&E);
		for(int i = 0;i <= P;i++)
		{
			dp1[i] = 0;
			dp2[i] = 0;
			a[i].clear();
		}
		for(int i = 0;i < E;i++)
		{
			int u,v;
		    scanf("%d%d",&u,&v);
		    a[u].push_back(v); 
	    }
	    Find1(1);
	   double ans = Find2(1);
	   //cout <<ans;
	   printf("%.2lf\n",ans);
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值