[dfs][概率] Jzoj P2941 贿赂
题解
- 题目大意:每个人有两个值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 }