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):
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL; const int MAXN = ;
const double EPS = 1e-; int T, n;
double dp[MAXN][( << MAXN) + ][MAXN];
double p[MAXN]; inline int sgn(double x) {
return (x > EPS) - (x < -EPS);
} int Tnext[ << MAXN][MAXN]; inline int next(int state, int x) {
if(Tnext[state][x] != -) return Tnext[state][x];
int ret = x;
while(true) {
if(++ret == n) ret = ;
if(state & ( << ret)) break;
}
return Tnext[state][x] = ret;
} inline int count(int state) {
int ret = ;
while(state) {
ret += state & ;
state >>= ;
}
return ret;
} int c[MAXN][MAXN];
double b[MAXN][MAXN], maxb[MAXN]; void dfs(int state, int cur) {
if(dp[cur][state][] != -) return ;
if(count(state) == ) {
for(int i = ; i < n; ++i) dp[cur][state][i] = (i == cur);
return ;
} for(int i = ; i < n; ++i) {
if((state & ( << i)) == ) continue;
for(int tar = next(state, i); tar != i; tar = next(state, tar)) {
int newState = state ^ ( << tar), nx = next(newState, i);
dfs(newState, nx);
}
} for(int i = ; i < n; ++i)
for(int j = ; j < n; ++j) b[i][j] = c[i][j] = ;
for(int i = ; i < n; ++i) maxb[i] = ; for(int i = ; i < n; ++i) {
if((state & ( << i)) == ) continue;
for(int tar = next(state, i); tar != i; tar = next(state, tar)) {
int newState = state ^ ( << tar), nx = next(newState, i);
maxb[i] = max(maxb[i], dp[nx][newState][i]);
}
for(int tar = next(state, i); tar != i; tar = next(state, tar)) {
int newState = state ^ ( << tar), nx = next(newState, i);
if(sgn(maxb[i] - dp[nx][newState][i]) == ) {
for(int k = ; k < n; ++k) {
++c[i][k];
b[i][k] += dp[nx][newState][k];
}
}
}
for(int k = ; k < n; ++k) b[i][k] /= c[i][k];
} for(int k = ; k < n; ++k) dp[cur][state][k] = p[cur] * b[cur][k]; for(int k = ; k < n; ++k) {
if((state & ( << k)) == ) continue;
int now = cur;
double tmp = , sum = ;
do {
now = next(state, now);
sum += tmp * p[now] * b[now][k];
tmp *= ( - p[now]);
} while(cur != now);
dp[cur][state][k] += sum / ( - tmp) * ( - p[cur]);
}
} void solve() {
dfs(( << n) - , );
for(int i = ; i < n - ; ++i) printf("%.2f ", * dp[][( << n) - ][i]);
printf("%.2f\n", * dp[][( << n) - ][n - ]);
} int main() {
memset(Tnext, -, sizeof(Tnext));
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
for(int i = ; i < n; ++i) scanf("%lf", &p[i]), p[i] /= ;
for(int i = ; i < n; ++i)
for(int j = ; j < ( << n); ++j) dp[i][j][] = -;
solve();
}
}
POJ 3028 Shoot-out(概率DP)的更多相关文章
- poj 3071 Football(概率dp)
id=3071">http://poj.org/problem? id=3071 大致题意:有2^n个足球队分成n组打比赛.给出一个矩阵a[][],a[i][j]表示i队赢得j队的概率 ...
- POJ 2096 Collecting Bugs (概率DP,求期望)
Ivan is fond of collecting. Unlike other people who collect post stamps, coins or other material stu ...
- POJ 2096 Collecting Bugs (概率DP)
题意:给定 n 类bug,和 s 个子系统,每天可以找出一个bug,求找出 n 类型的bug,并且 s 个都至少有一个的期望是多少. 析:应该是一个很简单的概率DP,dp[i][j] 表示已经从 j ...
- poj 2096 Collecting Bugs (概率dp 天数期望)
题目链接 题意: 一个人受雇于某公司要找出某个软件的bugs和subcomponents,这个软件一共有n个bugs和s个subcomponents,每次他都能同时随机发现1个bug和1个subcom ...
- poj 2096 Collecting Bugs 概率dp 入门经典 难度:1
Collecting Bugs Time Limit: 10000MS Memory Limit: 64000K Total Submissions: 2745 Accepted: 1345 ...
- POJ 3071 Football (概率DP)
概率dp的典型题.用dp[j][i]表示第j个队第i场赢的概率.那么这场要赢就必须前一场赢了而且这一场战胜了可能的对手.这些都好想,关键是怎么找出当前要算的队伍的所有可能的竞争对手?这个用异或来算,从 ...
- POJ 3071 Football:概率dp
题目链接:http://poj.org/problem?id=3071 题意: 给定n,有2^n支队伍参加足球赛. 给你所有的p[i][j],表示队伍i打败队伍j的概率. 淘汰赛制.第一轮(1,2)两 ...
- POJ 2096-Collecting Bugs(概率dp入门)
题意: 有n种bug和s种系统bug,每天发现一种bug(可能已经发现过了)所有种bug被发现的概率相同,求所有bug被发现的期望天数. 分析: dp[i][j]发现i种bug,j种系统bug期望天数 ...
- POJ 3071 Football 【概率DP】
Football Football Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3734 Accepted: 1908 ...
随机推荐
- canvas绘制圆角头像
如果你想绘制的网页包含一个圆弧形的头像的canvas图片,但是头像本身是正方形的,需要的方法如下:首先, 拿到头像在画布上的坐标和宽高:(具体怎么获取不在此做具体介绍) 使用canvas绘制圆弧动画 ...
- Linux中Zookeeper部署和集群部署
自己网上下载安装包,我下载的是tar.gz安装包直接解压,也可以下载rpm格式 1.下载zookeeper安装包,放到/usr/local/zookeeper安装包网上下载 2.解压文件tar -zx ...
- 使用bison和yacc制作脚本语言(2)
我们先来想一下语法 一般脚本语言不需要定义类型直接在赋值的时候确定 我们主要考虑一下变量的类型 a = 1; b = 1.1; c = "str"; 一般来讲,我们使用这三种类型, ...
- Qt——事件
1.常见事件 [1]鼠标事件 (1)坐标 x(),y(), 相对windows globalX() globalY() (2)获得点击 button() [2]键盘事件 [3]定时器事件 timerI ...
- 【数据结构】循环链表&&双向链表详解和代码实例
喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 01 循环链表 1.1 什么是循环链表? 前面介绍了单链表,相信大家还记得相关的概念.其实循环链表跟单链表也没有差别很多,只是在 ...
- Java多线程一些基础知识
最近复习了一些多线程方面的基础知识,做一下总结,多以自己的理解来文字叙述,如果有漏点或者理解错的地方,欢迎各位大佬多多指出: ps:线程分为用户线程和守护线程,当程序中的所有的用户线程都执行完了之后, ...
- 食物链_KEY
食物链 (eat.pas/c/cpp) [ 问题描述] 动物王国中有三类动物 A,B,C, 这三类动物的食物链构成了有趣的环形. A 吃 B, B 吃C, C 吃 A.现有 N 个动物, 以 1-N ...
- vcf-tools 笔记
vcf-query: 通过 vcf-query 提取DP (reads depth). ~/zengs/Tools/vcftools/perl/vcf-query -f '%CHROM\t%POS\t ...
- AIX7.1删除大批量文件(百万级、千万级)
假设/data/test目录下含有数百万上千万的文件需要删除,可以选择的方式如下: 1.如果文件名不包含空白符.引号等特殊字符,则可以使用如下命令: find /data/test -type f | ...
- 「日常训练」All Friends(POJ-2989)
题意 分析 代码 #include <iostream> #include <cstring> #include <algorithm> #define MP ma ...