【JZOJ2941】【NOIP2012模拟8.10】贿赂【DFS】
题目大意:
题目链接:https://jzoj.net/senior/#main/show/2941
议会里有个议员,每个议员有两个属性:级别和忠诚值。
现在你要在议会通过一个议案,一个议案通过当且仅当严格超过一半的议员投赞同票。一个议员投赞同票的几率就是忠诚值除以。
议员们有着奇怪的癖好:他们都喜欢吃糖。你带了个糖果用来贿赂议员,每个糖果的作用是使得某个议员的忠诚值增加。贿赂要在投票开始前完成。(注意任意议员的忠诚值不可能大于)
投票之后,如果议案没有通过,你就会很暴力地把投了反对票的所有议员暗杀掉。假设你要暗杀的议员集合是,那么成功率就是,其中是给定的常数,是中所有议员级别的和。当暗杀成功后你的议案就会获得通过。
现在要求最优贿赂方案下最大的成功几率是多大。
思路:
这道题只有,考虑用模拟或搜索。
分糖果的方法很明显是不确定的,所以需要用搜索累完成。对于任意一次搜索完毕后,每个议员又有了自己新的忠诚值。
接下来再次用搜索来求出期望。对于任意一个议员,他投赞成的几率是,反对的几率是。若赞成,那么就有赞成人数加一,反对的等级不变;反之等级加上,赞成人数不变。
最后搜索完时,若赞成人数超过一半,那么成功几率就是,如果没有超过一半,那么只有暗杀成功才行,即。
将所有的可能取一个最大值即可。时间复杂度不是很优秀,但是足够了。
代码:
#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;
}