您的位置:首页 > Web前端

HDU 2955 Robberies 和 HDU 1203 I NEED A OFFER!【思维转化 + 01背包】好题 !!!

2018-03-10 22:15 477 查看
这两道题非常相似, 思维和处理方式, 都是好题, 所以就放在一起说了….

HDU-2955

这一道要经典一些.

// 题意: 有n家银行, 每家银行对应着一个被抓的概率, 并且给出它能忍受的最低被抓概率, 问这个人最多可以抢多少钱.

// 思路: 原先以为只会精确到小数点后两位, 傻逼的就敲了, 后面才意识到是个浮点数, 没说是几位啊, 所以我们有两个问题要解决, 1:浮点数不好作为背包容量, 就算扩展成整数, 但是有可能会扩很大, 为10^(小数点位数), 2 : 概率不能单纯的相加, 应该有一个组合相乘的关系在里面, 比如抢了两家银行, 被抓的概率分别是a, b, 那么他被抓住的概率就有三种情况, a*(1-b) + b*(1-a) + a*b, 所以比较麻烦, 所以我们将概率全部转化为不被抓的概率, 那么我们要求的就是(1-a)*(1-b) 和 最初给定的那个概率(1-c)之间做比较取一个能抢到最多钱的即可, 也就是反过来将总的钱作为背包容量, 每家银行的钱作为体积, 不被抓的概率作为价值, dp[i] 就代表 抢到 i 这么多钱不被抓的概率是多少. 最后for一遍就可得到ans.

注意: 因为概率之间做的乘法, 并且这道题我们是将所有物品的价钱作为容量的, 又要去装每家银行的钱, 所以应该是一个恰好装满的情况, 所以初始化 dp[0] = 1.0, 其余的为0 (注意是乘!)….. 最后在扫一遍找ans即可.

AC Code

const int maxn = 1e4+5;
db dp[maxn];
int v[105];db w[105];
void solve()
{
int n; db rat;
while(cin >> rat >> n) {
rat = 1 - rat;
int tot = 0;
for (int i = 1 ; i <= n ; i ++) {
cin >> v[i] >> w[i];
w[i] = 1 - w[i];
tot += v[i];
}
Fill(dp, 0); dp[0] = 1;
for (int i = 1 ; i <= n ; i ++) {
for (int j = tot ; j >= v[i] ; j --) {
dp[j] = max(dp[j], dp[j-v[i]]*w[i]);
}
}
for (int i = tot ; i >= 0 ; i --) {
if (dp[i] > rat) {
cout << i << endl;
break;
}
}
}
}


HDU - 1203

// 题意: 有n所学校, 每所学校有一个花费 和 取得这所学校offer的概率. 现在他有m元, 问它最少被一所学校提供offer的最大概率是多少.

// 思路: 这道题比上面那道题要简单一些, 但是有些不同, 首先至少这个又是很多情况, 我们又要转化为求反面, 其次就是这个背包不一定要恰好装满, 所以我们应该吧每一个体积都初始化为1.0 , 然后做01背包即可, dp[i] 代表花费 i 元钱不拿到offer的最大概率, 那么ans = 1 - dp[tot] .

AC Code

const int maxn = 1e4+5;
db dp[maxn];
int v[maxn];db w[maxn];
void solve()
{
int n, tot;
while(cin >> tot >> n) {
if (tot + n == 0) break;
for (int i = 1 ; i <= n ; i ++) {
cin >> v[i] >> w[i];
w[i] = 1 - w[i];
}
for (int i = 0 ; i <= tot ; i ++) dp[i] = 1.0;
for (int i = 1 ; i <= n ; i ++) {
for (int j = tot ; j >= v[i] ; j --) {
dp[j] = min(dp[j], dp[j-v[i]]*w[i]);
}
}
db ans = (1-dp[tot]) * 100;
printf("%.1f%%\n", ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: