有$a$个普通球,$b$个超级球,有$n$个要捕捉的宝可梦,对于第$i$个宝可梦普通球的捕捉概率是$p_i$,超级球的捕捉概率是$u_i$,每种球只能扔一个到同一个宝可梦,同一个宝可梦可以被扔两种球。然后问在最优策略下捕捉个数的期望
考虑概率$dp$,发现状态无法简化到$n^2$级别,原来不是dp
假定每个宝可梦只能被扔一个球,那就是个匹配问题了,设$A$为普通球,$B$为超级球,源点向$A$,$B$连容量为球的个数,花费为$0$的边,$A,B$分别向每个精灵连容量为$1$,花费为$p_i$或者$u_i$的边,然后每个精灵向汇点连容量为$1$,费用为$0$的边,最大费用流的费用即为答案。
由于一个精灵能同时被扔两个球那么他被扔两个球时,捕捉的概率是$1-(1-p_i)times (1-u_i)$,化简得$p_i+u_i-p_i times u_i$,这样其实相当于$A,B$同时有容量为$1$的流流过这个精灵,如果没有$p_i times u_i$则可以每个精灵向汇点连两条边,每条边容量为$1$并且花费为$0$,然而处理这个$p_i times u_i$可以考虑把两条边中其中一条的费用改为$-p_i times u_i$,因为最大费用流跑最长路的时候肯定优先走$0$花费的那条,再走$-p_i times u_i$的这条,而走两条当且仅当两种球都扔向同一个精灵的时候,此时费用恰好和为$p_i+u_i-p_i times u_i$,得证。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
using namespace std; const double eps=1e-8; const int maxn=2000+5; int n,a,b; struct { int to; double cost;int cap,rev; edge(int to=0,double cost=0,int cap=0,int rev=0): to(to),cost(cost),cap(cap),rev(rev) {} }; vector<edge> g[maxn]; void addedge(int from,int to,int cap,double cost) { cost=-cost; g[from].push_back(edge(to,cost,cap,g[to].size())); g[to].push_back(edge(from,-cost,0,g[from].size()-1)); } double p[maxn],u[maxn]; int S,T,A,B; #define MP make_pair bool inque[maxn]; double dis[maxn]; int preve[maxn],prevv[maxn]; queue<int > q; double spfa() { for(int i=S;i<=B;i++) dis[i]=1e60,inque[i]=false; dis[S]=0;inque[S]=true; while(!q.empty()) q.pop(); q.push(S); memset(prevv,0,sizeof(prevv));memset(preve,0,sizeof(preve)); while(!q.empty()) { int u=q.front();q.pop();inque[u]=false; for(int i=0;i<(int)g[u].size();i++){ edge &e=g[u][i]; if(e.cap && dis[e.to]-(dis[u]+e.cost)>eps) { dis[e.to]=dis[u]+e.cost; preve[e.to]=i,prevv[e.to]=u; if(!inque[e.to]){ inque[e.to]=true; q.push(e.to); } } } } if(dis[T]>=1e60) return 0; int gap=INT_MAX; for(int i=T;i!=S;i=prevv[i]) gap=min(gap,g[prevv[i]][preve[i]].cap); for(int i=T;i!=S;i=prevv[i]){ edge &e=g[prevv[i]][preve[i]]; e.cap-=gap; g[i][e.rev].cap+=gap; } return dis[T]*(double)gap; } double MaxcostMaxflow() { double res=0,ret=0; while((res=spfa())!=0) ret+=res,res=0; return ret; } int main() { scanf("%d%d%d",&n,&a,&b); for(int i=1;i<=n;i++) scanf("%lf",&p[i]); for(int i=1;i<=n;i++) scanf("%lf",&u[i]); S=0,T=n+1,A=n+2,B=n+3; addedge(S,A,a,0),addedge(S,B,b,0); for(int i=1;i<=n;i++) addedge(A,i,1,p[i]),addedge(B,i,1,u[i]),addedge(i,T,1,0),addedge(i,T,1,-p[i]*u[i]); printf("%.4lfn",-MaxcostMaxflow()); return 0; } |
原文:大专栏 cf739E Gosha is hunting (flows)
原文地址:https://www.cnblogs.com/chinatrump/p/11615146.html
时间: 2024-10-07 23:50:21