题意:k个人投票选n个酒馆中的一个酒馆。他们选择投票数最高的酒馆。如果几个酒馆的票数相同,他们随机选择一个。
投票规则如下:一个人选该酒馆的概率是当前该酒馆的已经得到的票数比上当前已经投的所有的票数。
现在已经有几个人将票投完,问这种情况下,每个酒馆被选择的概率为多少。
思路:没有好的办法,我们必须票数从小到大,分别求每种情况下的概率。但是如果用DFS,会有很多不必要的重复计算,所以我们用BFS。同时,用一个数字来状态压缩投票的状态。
注意:需要非常注意的是,如果中间用int的话,题目中很多地方需要强制转换。这会导致很多不必要的时间消耗。所以,在代码中,我们直接用LL后缀。
代码如下:
#include <cstdio>
#include <map>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
const int MAXN = 7;
long long p[]= {1LL, 100LL, 10000LL, 1000000LL, 100000000LL };
double chance[MAXN] = { 0.0 };
int t[MAXN];
int N, K;
void bfs(long long start)
{
map<long long, double> m;
queue<long long>q;
m[start] = 100.0;
q.push(start);
while (!q.empty()){
long long now = q.front(); q.pop();
int total = 0;
long long tmp = now;
double pp = m[now];
for (int i = N; i > 0; --i)
{
t[i] = int(tmp % 100LL);
tmp /= 100LL;
total += t[i];
}
if (total == K)
{
int winner[MAXN] = { 0 };
int Max = t[1];
int sz = 0;
winner[sz++] = 1;
//printf("g");
for (int i = 2; i <= N; ++i)
{
if (Max == t[i])
winner[sz++] = i;
else if (t[i] > Max){
Max = t[i];
sz = 0;
winner[sz++] = i;
}
}
for (int i = 0; i < sz; ++i)
chance[winner[i]] += pp / (double)sz;
}
else {
for (int i = 1; i <= N; ++i)
{
long long next = now + p[N - i];
double c = (double)t[i] /(double) total;
map<long long,double>::iterator it = m.find(next);
if (it == m.end())
m[next] = pp * c, q.push(next);
else
it->second += pp * c;
//printf("0");
}
}
}
}
int main(void)
{
while (scanf("%d %d", &N, &K) != EOF){
long long start = 0LL;
for (int i = 0; i < N; ++i){
long long tmp;
scanf("%lld", &tmp);
start *= 100LL;
start += tmp;
}
memset(chance, 0, sizeof(chance));
bfs(start);
for (int i = 1; i <= N; ++i)
printf("pub %d: %.2f %%\n", i, chance[i]);
}
return 0;
}