zoukankan      html  css  js  c++  java
  • 【CF739E】Gosha is hunting

    题目

    题目链接:https://codeforces.com/problemset/problem/739/E
    你要抓神奇宝贝!
    现在一共有 (N) 只神奇宝贝。
    你有 (a) 个『宝贝球』和 (b) 个『超级球』。
    『宝贝球』抓到第 (i) 只神奇宝贝的概率是 (p_i) ,『超级球』抓到的概率则是 (u_i)
    不能往同一只神奇宝贝上使用超过一个同种的『球』,但是可以往同一只上既使用『宝贝球』又使用『超级球』(都抓到算一个)。
    请合理分配每个球抓谁,使得你抓到神奇宝贝的总个数期望最大,并输出这个值。
    (nleq 2000)

    思路

    考虑建立费用流模型。首先对于宝贝球和超级球分别建立一个点,从源点连一条流量为球的数量,费用为 (0) 的边来限制每一个球的数量。
    然后对于一个点 (i),从宝贝球的点连一条 ((1,p_i)) 的边,从超级球连一条 ((1,u_i)) 的边,然后从 (i) 向汇点连一条 ((1,0)) 的边,再连一条 ((1,-p_i imes u_i)) 的边。然后跑最大费用最大流。如果这个逼只用了一个球来抓,那么就会优先流费用为 (0) 的边,否则两条边都流,贡献即为 (p_i+u_i-p_iu_i),恰好是抓到它的期望。
    时间复杂度 (O(n^3))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=2010,M=20010,Inf=1e9;
    const double eps=1e-10;
    int n,a,b,A,B,S,T,tot,pre[N],head[N];
    double cost,p[2][N],dis[N];
    bool vis[N];
    
    struct edge
    {
    	int next,to,flow;
    	double cost;
    }e[M];
    
    void add(int from,int to,int flow,double cost)
    {
    	e[++tot]=(edge){head[from],to,flow,cost};
    	head[from]=tot;
    	swap(from,to);
    	e[++tot]=(edge){head[from],to,0,-cost};
    	head[from]=tot;
    }
    
    bool spfa()
    {
    	memset(dis,0xcf,sizeof(dis));
    	queue<int> q;
    	q.push(S); dis[S]=0;
    	while (q.size())
    	{
    		int u=q.front(); q.pop();
    		vis[u]=0;
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			int v=e[i].to;
    			if (e[i].flow && dis[v]<dis[u]+e[i].cost-eps)
    			{
    				dis[v]=dis[u]+e[i].cost; pre[v]=i;
    				if (!vis[v]) { vis[v]=1; q.push(v); }
    			}
    		}
    	}
    	return dis[T]>0;
    }
    
    void addflow()
    {
    	int minf=Inf;
    	for (int i=T;i!=S;i=e[pre[i]^1].to)
    		minf=min(minf,e[pre[i]].flow);
    	for (int i=T;i!=S;i=e[pre[i]^1].to)
    	{
    		e[pre[i]].flow-=minf;
    		e[pre[i]^1].flow+=minf;
    	}
    	cost+=dis[T]*minf;
    }
    
    void MCMF()
    {
    	while (spfa()) addflow();
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	tot=1; S=N-1; T=N-2; A=N-3; B=N-4;
    	scanf("%d%d%d",&n,&a,&b);
    	for (int i=1;i<=n;i++) scanf("%lf",&p[0][i]);
    	for (int i=1;i<=n;i++) scanf("%lf",&p[1][i]);
    	for (int i=1;i<=n;i++)
    	{
    		add(A,i,1,p[0][i]); add(B,i,1,p[1][i]);
    		add(i,T,1,0); add(i,T,1,-p[0][i]*p[1][i]);
    	}
    	add(S,A,a,0); add(S,B,b,0);
    	MCMF();
    	printf("%.10lf",cost);
    	return 0;
    }
    
  • 相关阅读:
    C++编译期间字节序判断
    解决:无法使用前导 .. 在顶级文件夹上退出
    手动脱WinUpack 壳实战
    浅谈cocos2dx(18) 中工厂模式
    手把手带你画一个 时尚仪表盘 Android 自己定义View
    Git实战(二)原理
    <html>
    Ubuntu局域网下利用client联网
    Desugar Scala(17) -- Option和for,以及脑子里发生的事情
    通过Canvas及File API缩放并上传图片完整演示样例
  • 原文地址:https://www.cnblogs.com/stoorz/p/14584653.html
Copyright © 2011-2022 走看看