【51nod1705】七星剑(成环DP)

博客详细介绍了如何使用成环动态规划解决一个剑升级问题,其中涉及剑从0星升至7星的期望花费计算。在动态规划的转移方程中存在环,但通过移项技巧可以简化问题,最终成功解决。

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

点此看题面

大致题意: 你要把一把剑从0星升至7星,有n颗宝石供你选择,第i颗宝石的价值是c[i],用第i颗宝石将剑从k-1星升至k星的成功率是prob[k][i],而失败后会掉lose[k][i],要你求出将剑升至7星的期望花费。


题解

看到这题,自然而然地就会想到用动态规划来做,而转移方程其实也很好推:

f[i]=min(f[i],f[i-1]+c[j]+(1-prob[i][j])*(f[i]-f[i-1-lose[i][j]));

其中f[i]表示将剑升至i星的期望花费

就这么简单?

B u t   w a i t   a   m i n u t e . . . But\ wait\ a\ minute... But wait a minute...

在转移方程中左边和右边同时出现了 f [ i ] f[i] f[i]

这就是传说中的成环 D P DP DP

那么成环 D P DP DP该怎么做呢?

其实在这道题目中有一个很简单的方法:移项。没错,就是我们初一上学期就接触过的移项。

通过移项,原转移方程就变成了

f[i]=min(f[i],(f[i-1]+c[j]-(1-prob[i][j])*f[i-1-lose[i][j]])/prob[i][j]);

这样不就直接水过了吗!(顺便吐槽一下 N ≤ 100 N≤100 N100这样的数据范围真是太水了)


代码
#include<bits/stdc++.h>
#define LL long long
#define min(x,y) ((x)<(y)?(x):(y))
#define N 100
using namespace std;
int n,c[N+5],lose[10][N+5];
double prob[10][N+5],f[10];
int read()
{
	int x=0,f=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	while(ch>='0'&&ch<='9') (x*=10)+=ch-'0',ch=getchar();
	return x*f;
}
int main(register int i,register int j,bool flag,bool ff)
{
	for(n=read(),i=1;i<=n;c[i++]=read());
	for(i=1,ff=true;i<=7;(flag?0:ff=false),++i)
		for(j=1,flag=false;j<=n;scanf("%lf",&prob[i][j]),flag|=prob[i][j++]>0.0);
	if(!ff) return puts("-1"),0;//判断是否存在不可能的情况
	for(i=1;i<=7;++i) 
		for(j=1;j<=n;lose[i][j++]=read());
	for(i=1;i<=7;++i)//DP过程,理解了再打真的很简单
		for(f[i]=1e18,j=1;j<=n;++j) 
			f[i]=min(f[i],(f[i-1]+c[j]-(1-prob[i][j])*f[i-1-lose[i][j]])/prob[i][j]);
	return printf("%.8lf",f[7]),0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值