UVAL 6267 Beer Pressure

题意: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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值