POJ 3028 Shoot-out(概率DP)

Description

This is back in the Wild West where everybody is fighting everybody. In particular, there are n cowboys, each with a revolver. These are rather civilized cowboys, so they have decided to take turns firing their guns until only one is left standing. Each of them has a given probability of hitting his target, and they all know each other’s probability. Furthermore, they are geniuses and always know which person to aim at in order to maximize their winning chance, so they are indeed peculiar cowboys. If there are several equally good targets, one of those will be chosen at random. Note that a cowboy’s code of ethics forces him to do his best at killing one of his opponents, even if intentionally missing would have increased his odds (yes, this can happen!)

Input

On the first line of the input is a single positive integer t, telling the number of test cases to follow. Each case consists of one line with an integer 2 ≤ n ≤ 13 giving the number of cowboys, followed by n positive integers giving hit percentages for the cowboys in the order of their turns.

Output

For each test case, output one line with the percent probabilities for each of them surviving, in the same order as the input. The numbers should be separated by a space and be correctly rounded to two decimal places.

 

题目大意:n个枪手,均有一个命中率,从第一位开始,每次下一位开枪射击一个人。问每个人的生存率是多少,枪手总会朝着对自己最有利的人开枪,但一定要开枪,不能向自己开枪,如果有多个最有利的人,随机向其中一个开枪。

思路:O(n^4*2^n)水过去的……所以思路就不怎么讲了……(next每次算会TLE,先预处理出来依然TLE……)现在实在想不到什么好方法先这样吧……

PS:贴一下做题时候的草稿

b[i]为i命中的胜率
a[i]为i不命中的胜率
p[i]为i的命中率
q[i]为1-p[i]
a[i] = p[i+1] * b[i+1] + q[i+1] * a[i+1]
= p[i+1] * b[i+1] + q[i+1] * (p[i+2] * b[i+2] + q[i+2] * a[i+2])
= p[i+1] * b[i+1] + q[i+1] * p[i+2] * b[i+2] + q[i+1] * q[i+2] * a[i+2]
= p[i+1] * b[i+1] + q[i+1] * p[i+2] * b[i+2] + ……
+ pro{q[i+1] .. q[i-1]} * p[i] * b[i] + pro{q[i+1] .. q[i]} * a[i]
a[i] = (p[i+1] * b[i+1] + q[i+1] * p[i+2] * b[i+2] + ……
+ pro{q[i+1] .. q[i-1]} * p[i] * b[i]) / (1 - pro{q[i+1] .. q[i]})

 

代码(2641MS):

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <cstring>
  5 using namespace std;
  6 typedef long long LL;
  7 
  8 const int MAXN = 13;
  9 const double EPS = 1e-8;
 10 
 11 int T, n;
 12 double dp[MAXN][(1 << MAXN) + 10][MAXN];
 13 double p[MAXN];
 14 
 15 inline int sgn(double x) {
 16     return (x > EPS) - (x < -EPS);
 17 }
 18 
 19 int Tnext[1 << MAXN][MAXN];
 20 
 21 inline int next(int state, int x) {
 22     if(Tnext[state][x] != -1) return Tnext[state][x];
 23     int ret = x;
 24     while(true) {
 25         if(++ret == n) ret = 0;
 26         if(state & (1 << ret)) break;
 27     }
 28     return Tnext[state][x] = ret;
 29 }
 30 
 31 inline int count(int state) {
 32     int ret = 0;
 33     while(state) {
 34         ret += state & 1;
 35         state >>= 1;
 36     }
 37     return ret;
 38 }
 39 
 40 int c[MAXN][MAXN];
 41 double b[MAXN][MAXN], maxb[MAXN];
 42 
 43 void dfs(int state, int cur) {
 44     if(dp[cur][state][0] != -1) return ;
 45     if(count(state) == 1) {
 46         for(int i = 0; i < n; ++i) dp[cur][state][i] = (i == cur);
 47         return ;
 48     }
 49 
 50     for(int i = 0; i < n; ++i) {
 51         if((state & (1 << i)) == 0) continue;
 52         for(int tar = next(state, i); tar != i; tar = next(state, tar)) {
 53             int newState = state ^ (1 << tar), nx = next(newState, i);
 54             dfs(newState, nx);
 55         }
 56     }
 57 
 58     for(int i = 0; i < n; ++i)
 59         for(int j = 0; j < n; ++j) b[i][j] = c[i][j] = 0;
 60     for(int i = 0; i < n; ++i) maxb[i] = 0;
 61 
 62     for(int i = 0; i < n; ++i) {
 63         if((state & (1 << i)) == 0) continue;
 64         for(int tar = next(state, i); tar != i; tar = next(state, tar)) {
 65             int newState = state ^ (1 << tar), nx = next(newState, i);
 66             maxb[i] = max(maxb[i], dp[nx][newState][i]);
 67         }
 68         for(int tar = next(state, i); tar != i; tar = next(state, tar)) {
 69             int newState = state ^ (1 << tar), nx = next(newState, i);
 70             if(sgn(maxb[i] - dp[nx][newState][i]) == 0) {
 71                 for(int k = 0; k < n; ++k) {
 72                     ++c[i][k];
 73                     b[i][k] += dp[nx][newState][k];
 74                 }
 75             }
 76         }
 77         for(int k = 0; k < n; ++k) b[i][k] /= c[i][k];
 78     }
 79 
 80     for(int k = 0; k < n; ++k) dp[cur][state][k] = p[cur] * b[cur][k];
 81 
 82     for(int k = 0; k < n; ++k) {
 83         if((state & (1 << k)) == 0) continue;
 84         int now = cur;
 85         double tmp = 1, sum = 0;
 86         do {
 87             now = next(state, now);
 88             sum += tmp * p[now] * b[now][k];
 89             tmp *= (1 - p[now]);
 90         } while(cur != now);
 91         dp[cur][state][k] += sum / (1 - tmp) * (1 - p[cur]);
 92     }
 93 }
 94 
 95 void solve() {
 96     dfs((1 << n) - 1, 0);
 97     for(int i = 0; i < n - 1; ++i) printf("%.2f ", 100 * dp[0][(1 << n) - 1][i]);
 98     printf("%.2f\n", 100 * dp[0][(1 << n) - 1][n - 1]);
 99 }
100 
101 int main() {
102     memset(Tnext, -1, sizeof(Tnext));
103     scanf("%d", &T);
104     while(T--) {
105         scanf("%d", &n);
106         for(int i = 0; i < n; ++i) scanf("%lf", &p[i]), p[i] /= 100;
107         for(int i = 0; i < n; ++i)
108             for(int j = 0; j < (1 << n); ++j) dp[i][j][0] = -1;
109         solve();
110     }
111 }
View Code

 

posted @ 2013-11-16 21:03  Oyking  阅读(660)  评论(0编辑  收藏  举报