【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星的期望花费

就这么简单?But wait a minute…在转移方程中左边和右边同时出现了f[i]!

这就是传说中的成环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这样的数据范围真是太水了)

代码如下:

#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;
}

猜你喜欢

转载自blog.csdn.net/chenxiaoran666/article/details/81119408