1. 程式人生 > >【NOIP2018模擬賽2018.10.20】死宅與陷阱

【NOIP2018模擬賽2018.10.20】死宅與陷阱

題目

在這裡插入圖片描述
在這裡插入圖片描述

題解

–是一道典型的期望dp題
一個點的權值要對答案產生貢獻,那麼那條路徑必須要經過它
所以我們反向建圖(避免重複遍歷),dp每個點經過它的概率
把概率最大的t的點追加陷阱(貪心),除了s
最後加起來就好了

程式碼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1e6+5
; int n,m,p,s,t; int head[MAXN],to[MAXN],next[MAXN],cnt; double w[MAXN],d[MAXN],ans; int v[MAXN],a[MAXN],du[MAXN]; void add(int u,int v,double l){ cnt++; next[cnt]=head[u]; to[cnt]=v; w[cnt]=l; head[u]=cnt; du[v]++; } double dfs(int x){ for(int i=head[x];i;i=next[i]){ int y=to[i]; if(d[
y]!=0) d[x]+=d[y]*w[i]; else d[x]+=dfs(y)*w[i]; } return d[x]; } bool comp(const int &a,const int &b){ return d[a]>d[b]; } int main(){ // freopen("trap.in","r",stdin); // freopen("trap.out","w",stdout); cin>>n>>m>>p>>s>>t; for(int i=1;i<=n;i++){ scanf
("%d",&v[i]); a[i]=i; } for(int i=1;i<=m;i++){ int a,b; double c; scanf("%d%d%lf",&a,&b,&c); add(b,a,c); } d[s]=1.00; for(int i=1;i<=n;i++) if(!du[i]) d[i]=dfs(i); sort(a+1,a+1+n,comp); for(int i=1;i<=t;i++) v[a[i+1]]+=p; for(int i=1;i<=n;i++) ans+=d[i]*(double)v[i]; printf("%.3lf",ans); return 0; }