题意:
给定n个酒吧, 然后有k个学生投票今晚去哪个酒吧, 然后会有a个(a<=k)学生先投票了, 先投的票会影响后面的人投票的概率, 求每个酒吧今晚去的概率。
分析:
我们可以从最初的状态开始广搜, 由于搜索中会有很多重复的状态, 我们用一个map去储存这些状态, 如果map中没有这个状态再将他入队。由于搜索量很大, 如果用vector作为队列元素的话会MLE, 我们可以将最多5个酒吧,每个酒吧不超过两位的投票数映射成一个10位的long long作为队列元素, 出队时候再还原成n个投票数,最终输出所有的结果即可。
1 #include<bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 const int inf = 1e9 + 7; 5 const int maxn = 8; 6 double possible[maxn]; 7 int temp[maxn]; 8 const LL P[] = {1LL,100LL,10000LL,1000000LL,100000000LL}; 9 int n, k; 10 int bfs(LL start){ 11 map<LL, double> m;//记录状态 12 m[start] = 100.0;//开始状态 13 queue<LL> q; 14 q.push(start); 15 while(!q.empty()){ 16 LL u = q.front(); q.pop(); 17 double pp = m[u]; 18 int tot = 0; 19 LL tmp = u; 20 for(int i = n; i > 0; i--){//将long long 还原成数组 21 temp[i] = int(tmp%100LL); 22 tmp /= 100LL; 23 tot += temp[i]; 24 } 25 if(tot == k){//已经投完票, 选出票数最多的将概率分享。 26 int winner[maxn] = {0}; 27 int Max = temp[1]; 28 int chosen = 0; 29 winner[chosen++] = 1; 30 for(int i = 2; i <= n; i++){ 31 if(Max == temp[i])winner[chosen++] = i; 32 else if(temp[i] > Max){ 33 Max = temp[i]; 34 chosen = 0; 35 winner[chosen++] = i; 36 } 37 } 38 for(int i = 0; i < chosen; i++) 39 possible[winner[i]] += pp/(double)chosen; 40 } 41 else{ 42 for(int i = n; i >= 1; i--){ 43 LL v = u + P[n - i]; 44 double c = (double)temp[i] / (double)tot; 45 46 map<LL, double> :: iterator it = m.find(v); 47 if(it == m.end()) 48 m[v] = pp * c, q.push(v);//如果没出现这个状态就入队 49 else 50 it->second += pp * c;//出现过直接在这个状态上面加 51 } 52 } 53 } 54 } 55 int main(){ 56 while(~scanf("%d %d", &n, &k)){ 57 memset(possible,0,sizeof(possible)); 58 LL u = 0; 59 for(int i = 0; i < n; i++){int t;scanf("%d", &t); u *= 100LL, u += t;}//映射成一个10位long long 60 bfs(u); 61 for(int i = 1;i <= n; i++) printf("pub %d: %.2f %%\n",i, possible[i]); 62 } 63 }