LOJ-1265 Island of Survival

Island of Survival

题目链接

题目大意:现在你所在的岛上有 t t t 只老虎, d d d 只鹿。

每一天随机选出两只动物,将会发生下列五种情况:
1.你与老虎,那你没了。
2.老虎与鹿,鹿没了。
3.两只鹿,相安无事。
4.你与鹿,你可以杀死或者令其存活。
5.两只老虎,互相残杀,两只都没了。

现在问你能活下去的概率。对于第四点,你会让你的存活几率尽量大而选择是否让鹿存活。

显然,我们首先定义 f [ i ] [ j ] f[i][j] f[i][j] 为 岛上有 i i i 只老虎, j j j 只鹿时,我们能存活的概率。

此题的关键就在于转移时候的细节。

毋庸置疑, f [ 0 ] [ j ] = 1 f[0][j]=1 f[0][j]=1

对于其它情况而言,我们枚举下一天的情况对其进行状态的转移。

对于某一天,我们能活下去的情况就是除 1 1 1 以外的四种情况,那么我们一种一种来看。

首先设 d = ( i + j + 1 ) × ( i + j ) d=(i + j + 1) × (i + j) d=(i+j+1)×(i+j)

对于情况 2 2 2 ,首先 i > 0 , j > 0 i>0,j>0 i>0,j>0 ,其发生的概率 p = 2 × i × j d p=\frac{2×i×j}{d} p=d2×i×j ,所以在这种状态下,对 f [ i ] [ j ] f[i][j] f[i][j] 我们存活的概率贡献为 p × f [ i ] [ j − 1 ] p×f[i][j-1] p×f[i][j1]

情况 5 5 5 与上面同理分析,其 p = i × ( i − 1 ) d p=\frac{i×(i-1)}{d} p=di×(i1) ,其贡献为 p × f [ i − 2 ] [ j ] p×f[i-2][j] p×f[i2][j]

此题细节就在于情况 4 4 4 ,我们到底如何选择呢,我们发现我们无法直接确定选哪一种。一开始觉得这样不没办法做下去了,但是我们想一想,我们的选择基于什么呢?基于我们需要存活概率更高, 也就是 f [ i ] [ j ] f[i][j] f[i][j]更大 ,那么问题就简单了,那么我把这两种情况都计算一遍,都得出一个 f [ i ] [ j ] f[i][j] f[i][j] ,更优的那个不就是是我们的选择了嘛。

最后根据具体情况联系情况 3 3 3列出转移等式,最后解出 f [ i ] [ j ] f[i][j] f[i][j] 即可(有的情况也不用解,只要转移等式的右侧没有 f [ i ] [ j ] f[i][j] f[i][j] 就自然不用解方程)

#include <bits/stdc++.h>

using namespace std;

const int N = 1e3 + 5;

int cs;

double f[N][N];

void init(int n) {
	for (int i = 0; i <= n; ++i) f[0][i] = 1;
	for (int i = 1; i <= n; ++i) {
		for (int j = 0; j <= n; ++j) {
			double p = 0, d = 1.0 * (i + j + 1) * (i + j);
			if (i && j) p += (2.0 * i * j) / d * f[i][j - 1];
			if (i > 1) p += (i * (i - 1)) / d * f[i - 2][j];
			if (j) {
				double num1, num2;
				if (j > 1) {
					num1 = p * d / (d - j * (j - 1) - 2.0 * j);
					p += 2.0 * j / d * f[i][j - 1];
					num2 = p * d / (d - j * (j - 1));
					f[i][j] = max(num1, num2);
				}
				else {
					num1 = p * d / (d - 2.0 * j);
					num2 = p + (2.0 * j) / d * f[i][j - 1];
					f[i][j] = max(num1, num2);
				}
			}
			else {
				f[i][j] = p;
			}
		}
	}
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#endif
	init(1000);
	int T;
	scanf("%d", &T);
	while(T--) {
		int t, d;
		scanf("%d%d", &t, &d);
		printf("Case %d: %.10f\n",++cs,  f[t][d]);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值