POJ 3028 Shoot-out(概率DP)

本文针对一群枪手按顺序轮流射击的问题进行分析,每个枪手都有特定的命中概率,并且会根据当前局势选择最佳目标以最大化自身存活几率。文章提供了一种复杂度为O(n^4*2^n)的解决方案,并附带详细的算法推导过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

 

转载于:https://www.cnblogs.com/oyking/p/3427160.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值