【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;
} 
原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998393.html