• 【JZOJ2941】【NOIP2012模拟8.10】贿赂【DFS】


    题目大意:

    题目链接:https://jzoj.net/senior/#main/show/2941
    议会里有NN个议员,每个议员有两个属性:级别和忠诚值。
    现在你要在议会通过一个议案,一个议案通过当且仅当严格超过一半的议员投赞同票。一个议员投赞同票的几率就是忠诚值除以100100
    议员们有着奇怪的癖好:他们都喜欢吃糖。你带了KK个糖果用来贿赂议员,每个糖果的作用是使得某个议员的忠诚值增加1010。贿赂要在投票开始前完成。(注意任意议员的忠诚值不可能大于100100
    投票之后,如果议案没有通过,你就会很暴力地把投了反对票的所有议员暗杀掉。假设你要暗杀的议员集合是SS,那么成功率就是AA+Bfrac{A}{A+B},其中AA是给定的常数,BBSS中所有议员级别的和。当暗杀成功后你的议案就会获得通过。
    现在要求最优贿赂方案下最大的成功几率是多大。


    思路:

    这道题nn只有99,考虑用模拟或搜索。
    分糖果的方法很明显是不确定的,所以需要用搜索累完成。对于任意一次搜索完毕后,每个议员又有了自己新的忠诚值bib_i
    接下来再次用搜索来求出期望。对于任意一个议员ii,他投赞成的几率是bi%b_i\%,反对的几率是100bi%100-b_i\%。若赞成,那么就有赞成人数加一,反对的等级不变;反之等级加上aia_i,赞成人数不变。
    最后搜索完时,若赞成人数超过一半,那么成功几率就是100%100\%,如果没有超过一半,那么只有暗杀成功才行,即AA+Bfrac{A}{A+B}
    将所有的可能取一个最大值即可。时间复杂度不是很优秀,但是足够了。


    代码:

    #include <cstdio>
    #include <iostream>
    using namespace std;
    
    int n,m;
    double A,ans,a[10],b[10];
    
    double dfs2(int x,int sum,double B)  //求期望
    {
    	if (x>n)
    	{
    		if (sum*2>n) return 1.0;  //成功
    		return A/(A+B);  //不成功
    	}
    	return b[x]*dfs2(x+1,sum+1,B)+(1.0-b[x])*dfs2(x+1,sum,B+a[x]);
    	  //赞成几率*赞成成功率+反对几率*反对成功率。
    }
    
    void dfs1(int x,int s)  //搜索糖果不解释
    {
    	if (x>n)
    	{
    		ans=max(ans,dfs2(1,0,0));
    		return;
    	}
    	for (int i=0;i<=min(10-(int)(b[x]*10.0),s);i++)
    	{
    		b[x]+=(double)i*0.1;
    		dfs1(x+1,s-i);
    		b[x]-=(double)i*0.1;
    	}
    }
    
    int main()
    {
    	scanf("%d%d%lf",&n,&m,&A);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%lf%lf",&a[i],&b[i]);
    		b[i]/=100.0;
    	}
    	dfs1(1,m);
    	printf("%0.6lf",ans);
    	return 0;
    } 
    
  • 相关阅读:
    【2018.10.3】万圣节的快递
    【2018.10.3】万圣节的入场券
    【2018.10.2】纸条
    【2018.10.2】菌落合并
    【2018.10.2】Note of CXM
    【2018.10.1】【JSOI2016】最佳团体(bzoj4753)
    【2018.10.1】「JOI 2014 Final」年轮蛋糕
    【2018.9.26】K-D Tree详解
    Python中的numpy模块解析
    Python中xlrd模块解析
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998393.html
Copyright © 2020-2023  润新知