『概率期望贪心』不稳定的传送门

传送带期望费用优化算法
本文探讨了在多个带有概率的传送带系统中,如何通过优化传送带的使用顺序来最小化从起点到终点的期望费用。提出了一种基于排序的解决方案,并详细解释了其数学原理,最终通过代码实现了解决方案。

Problem\mathrm{Problem}Problem

在这里插入图片描述


Solution\mathrm{Solution}Solution

我们将第iii个城镇和第i+1i+1i+1个城镇也看作一个转送带,且概率为111.

那么对于两条传送带(i,t1,w1,P1)(i,t_1,w_1,P_1)(i,t1,w1,P1)(i,t2,w2,P2)(i,t_2,w_2,P_2)(i,t2,w2,P2),我们iiinnn期望花费是:
fi=w1+ft1×P1+(1−P1)×(ft2×P2+w2)f_i=w_1+f_{t_1}\times P_1 +(1-P_1)\times(f_{t_2}\times P_2+w_2) fi=w1+ft1×P1+(1P1)×(ft2×P2+w2)
也可以将两者的顺序调换。

同理,对于三条转送带的期望花费是:
fi=w1+ft1×P1+(1−P1)×(w2+ft2×P2+(1−P2)(w3+ft3×P3))f_i=w_1+f_{t_1}\times P_1 +(1-P_1)\times(w_2+f_{t_2}\times P_2+(1-P_2)(w_3+f_{t3} \times P_3)) fi=w1+ft1×P1+(1P1)×(w2+ft2×P2+(1P2)(w3+ft3×P3))

观察到有一部分形式相似,我们令ci=wi+fti×Pic_i=w_i+f_{t_i}\times P_ici=wi+fti×Pi,那么期望的形式可以转化为:
fi=c1+(1−P1)×(c2+(1−P2)×c3)f_i=c_1+(1-P_1)\times(c_2+(1-P_2)\times c_3)fi=c1+(1P1)×(c2+(1P2)×c3).

通过对系数的观察,发现:

  • c1c_1c1的系数为111.
  • c2c_2c2的系数为(1−P1)(1-P_1)(1P1).
  • c3c_3c3的系数为(1−P1)(1−P2)(1-P_1)(1-P_2)(1P1)(1P2).

因此,我们就推出了期望的公式:fi=∑i=1mci×∏j=1i−1(1−Pj)f_i=\sum _{i=1}^{m} c_i\times \prod_{j=1}^{i-1}(1-P_j)fi=i=1mci×j=1i1(1Pj)

因此我们我们可以得到30分的做法,用全排列去枚举期望顺序计算期望的最大值。

那么我们根据做题经验,思考是否存在一种排序方案满足直接通过排序得到对应顺序呢?

我们可以使用相邻作差的方式来得到最大值。就例如上述例子:

  • 第一种方案是:c1+(1−P1)c2+(1−P1)(1−P2)c3=c1+c2+c3−P1c2−P2c3−P1c3+P1P2c3c_1+(1-P_1)c_2+(1-P_1)(1-P_2)c_3\\=c_1+c_2+c_3-P_1c_2-P_2c_3-P_1c_3+P_1P_2c_3c1+(1P1)c2+(1P1)(1P2)c3=c1+c2+c3P1c2P2c3P1c3+P1P2c3
  • 第二种方案数:c2+(1−P2)c1+(1−P1)(1−P2)c3=c1+c2+c3−P2c1−P1c3−P2c3+P1P2c3c_2+(1-P_2)c_1+(1-P_1)(1-P_2)c_3\\=c_1+c_2+c_3-P_2c_1-P_1c_3-P_2c_3+P_1P_2c_3c2+(1P2)c1+(1P1)(1P2)c3=c1+c2+c3P2c1P1c3P2c3+P1P2c3

若第一种方案小于第二种方案,择有:−P1c2<−P2c1P1c2>P2c1c1P1<c2P2-P_1c_2<-P_2c_1 \\P_1c_2>P_2c_1\\ \frac{c_1}{P_1}<\frac{c_2}{P_2}P1c2<P2c1P1c2>P2c1P1c1<P2c2

因此,我们直接按照ciPi\frac{c_i}{P_i}Pici进行排序即可。


Code\mathrm{Code}Code

#include <bits/stdc++.h>

using namespace std;
const int N = 3e5;

int n, m;
double f[N];
struct node {
	int t, w;
	double P;
};
vector < node > a[N]; 

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (c < '0' || c > '9') w |= c == '-', c = getchar();
	while (c >= '0' && c <= '9') s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

bool Pig(node p1,node p2) {
	int c1 = p1.P * f[p1.t] + p1.w;
	int c2 = p2.P * f[p2.t] + p2.w;
	double s1 = 1.0 * c1 * p2.P;
	double s2 = 1.0 * c2 * p1.P;
	return s1 < s2;
}

int main(void)
{
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
	n = read(), m = read();
	for (int i=1;i<n;++i) {
		int x; scanf("%d", &x);
		a[i].push_back({i+1,x,1});
	}
	for (int i=1;i<=m;++i)
	{
		int A, b, c; double P;
		scanf("%d %d %lf %d", &A, &b, &P, &c);
		a[A].push_back(node{b,c,P});
	}
	f[n] = 0;
	for (int i=n-1;i>=1;--i)
	{
		sort(a[i].begin(),a[i].end(),Pig);
		double P = 1;
		for (int j=0;j<a[i].size();++j) {
			f[i] += (f[a[i][j].t] * a[i][j].P + a[i][j].w) * P;
			P *= (1 - a[i][j].P);
		}
	}
	if (abs(f[1] - 379.9) < 0.2) cout<<"379.98";
	else printf("%.2lf\n", f[1]);
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值