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

题目大意:

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


思路:

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


代码:

#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;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值