1. 程式人生 > >【CodeM初賽B輪】F 期望DP

【CodeM初賽B輪】F 期望DP

發生 ble 題解 mes continue 現在 cst string 情況

【CodeM初賽B輪】F

題目大意:有n個景點,m條無向邊,經過每條邊的時間需要的時間是l,在每個景點遊覽花費的時間是t,遊覽完每個景點可以獲得的滿意度是h。你的總時間為k,起初你等概率的選擇遊覽一個景點,然後每次等概率的前往一個相鄰的景點遊覽,當你剩余時間不夠遊覽一個相鄰的景點時就結束遊覽。問所獲得的滿意度的期望值。(本題強行詢問兩次~)

n<=100,總時間<=500

題解:顯然的期望DP啊,不過本題的細節比較多,我這裏只說一些細節吧~

用f[i][j]表示遊覽完景點i,還剩時間j,所獲得的期望滿意度。顯然f[i][j]可以由相鄰的景點轉移而來,不過可沒那麽簡單~

你還需要維護p[i][j]表示遊覽完景點i,還剩時間j,這種情況發生的概率;d[i][j]表示遊覽完景點i,還剩時間j,此時景點i的出度(顯然,一個點的出度在不同時間是不一樣的。)現在你才能進行狀態轉移。

$f[i][k]=\sum {f[j][k+l[i][j]+t[i]]\over d[j][k+l[i][j]+t[i]]}+h[i]*p[i][k]$

答案就是所有出度為0的狀態的f之和(顯然它們的p之和=1,如果你的程序正確的話~)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
typedef long double ld;
int n,m,T;
int map[110][110],t[110],h1[110],h2[110],d[110][500];
ld ans,ans1,ans2,p[110][500],f1[110][500],f2[110][500];
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
int main()
{
	n=rd(),m=rd(),T=rd();
	int i,j,k,a,b,c,flag;
	for(i=1;i<=n;i++)	t[i]=rd(),h1[i]=rd(),h2[i]=rd();
	for(i=1;i<=m;i++)	a=rd(),b=rd(),map[a][b]=map[b][a]=rd();
	for(i=1;i<=n;i++)	p[i][T-t[i]]=1.0/n;
	for(k=T-1;k>=0;k--)
	{
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=n;j++)	if(map[i][j]&&k>=map[i][j]+t[j])	d[i][k]++;
			for(j=1;j<=n;j++)
			{
				if(!map[i][j])	continue;
				c=k+map[i][j]+t[i];
				if(c>=T)	continue;
				p[i][k]+=p[j][c]/d[j][c];
				f1[i][k]+=f1[j][c]/d[j][c];
				f2[i][k]+=f2[j][c]/d[j][c];
			}
			f1[i][k]+=p[i][k]*h1[i];
			f2[i][k]+=p[i][k]*h2[i];
			if(!d[i][k])	ans+=p[i][k],ans1+=f1[i][k],ans2+=f2[i][k];
		}
	}
	printf("%.5lf %.5lf",(double)ans1,(double)ans2);
	return 0;
}

【CodeM初賽B輪】F 期望DP