[dfs][概率] Jzoj P2941 贿赂

Description

议会里有N个议员,每个议员有两个属性:级别和忠诚值。


现在你要在议会通过一个议案,一个议案通过当且仅当严格超过一半的议员投赞同票。一个议员投赞同票的几率就是忠诚值除以100。


议员们有着奇怪的癖好:他们都喜欢吃糖。你带了K个糖果用来贿赂议员,每个糖果的作用是使得某个议员的忠诚值增加10。贿赂要在投票开始前完成。(注意任意议员的忠诚值不可能大于100)


投票之后,如果议案没有通过,你就会很暴力地把投了反对票的所有议员暗杀掉。假设你要暗杀的议员集合是S,那么成功率就是A/(A+B);其中A是给定的常数,B是S中所有议员级别的和。当暗杀成功后你的议案就会获得通过。


现在要求最优贿赂方案下最大的成功几率是多大。


 

 

Input

第一行三个整数N,K和A,意义如题目所述;


接下来N行每行两个整数ai,bi分别表示每个议员的级别和忠诚值。


 

Output

一个实数表示可能的最大成功几率。保留6位小数。


 

 

Sample Input

5 3 100
11 80
14 90
23 70
80 30
153 70

Sample Output

0.962844
 

Data Constraint

 
 

Hint

对于40%的数据,保证N,K≤5


对于100%的数据,保证N,K≤9,A,ai≤9999,bi是10的倍数

 

 

题解

  • 题目大意:每个人有两个值a[i],b[i]为各自的等级和忠诚值,现在有k颗糖果分配出去(一个人可以拿多颗),每颗可以使一个人的忠诚值+10,若得到票数的概率没有超过一半,那么要暗杀,暗杀成功的概率为A/(A+B),其中B是所有人的等级和,问成功的概率
  • 首先,这个数据范围十分感人
  • 考虑直接dfs来枚举分配糖果的方案,这样的时间复杂度是O(n!)的
  • 那么对于n个人的忠诚值,如何求他成功的概率
  • 考虑可以递归来做,每个人就有两种情况,一种是选,就乘上选的概率,一种是不选,那就乘上不选的概率
  • 如果递归到最后的一种情况中,所得票数没有超过半数,那么就要乘上暗杀成功的概率
  • 最后所有概率取一个最大值就好了

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #define N 10
 5 using namespace std;
 6 int n,k,A,a[N],b[N];
 7 double ans;
 8 double work(int x,int y,int B)
 9 {
10     if (x>n) { if (y*2>n) return 1.0; else return 1.0*A/(A+B); }
11     return 1.0*b[x]/100*work(x+1,y+1,B)+1.0*(1-1.0*b[x]/100)*work(x+1,y,B+a[x]);
12 }
13 void dfs(int x,int y)
14 {
15     if (x==n)
16     {
17         if (y!=0) b[x]+=y*10;
18         if (b[x]<=100) ans=max(ans,work(1,0,0));
19         b[x]-=y*10; return;
20     }
21     for (int i=0;i<=y;i++)
22     {
23         b[x]+=i*10;
24         if (b[x]<=100) dfs(x+1,y-i); else  { b[x]-=i*10; break; }
25         b[x]-=i*10;
26     }
27 }
28 int main()
29 {
30     scanf("%d%d%d",&n,&k,&A);
31     for (int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
32     dfs(1,k),printf("%.6lf",ans);
33 }

 

posted @ 2019-01-19 15:55  BEYang_Z  阅读(126)  评论(0编辑  收藏  举报