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

点此看题面

大致题意: 你要把一把剑从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
#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;
}

你可能感兴趣的:(51nod,动态规划)