POJ 1042(DP+路径打印)

被一个max和一个inline卡常了。。。

dp[i][j]表示前i个湖用时j个单位时间时钓到的最多鱼数。
状态转换方程为:dp[i][j]=Math.max(dp[i-1][ j-k-t[i] ]+fishs , dp[i][j]),
t[i]为从第i-1个湖到第i个湖所用的时间,fishs为在k个时间单位内小明在第i个湖钓到的鱼数;
递推填表时,有很多细节要注意,见代码注释
AC代码

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=1e3+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
#define ls (i<<1)
#define rs (i<<1|1)
#define fi first
#define se second
#define mk make_pair
#define mem(a,b) memset(a,b,sizeof(a))
LL read()
{
    LL x=0,t=1;
    char ch;
    while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
    while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
    return x*t;
}
int f[N],d[N],t[N],n,m;
int dp[30][300],path[30][300];
inline int cal(int i,int k)
{
    if(d[i]&&k>f[i]/d[i]+1) k=f[i]/d[i]+1;
    return k?k*(2*f[i]-(k-1)*d[i])/2:0;
}
int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    int test=0;
    while(scanf("%d",&n)!=EOF&&n)
    {
        m=read();
        mem(dp,0);
        mem(path,0);
        m*=12;
        for(int i=1;i<=n;i++) f[i]=read();
        for(int i=1;i<=n;i++) d[i]=read();
        for(int i=2;i<=n;i++) t[i]=read();
        t[1]=0;
        int T=0;
        for(int i=1;i<=n;i++)
        {
            T+=t[i];
            if(T>m) break;
            for(int j=T;j<=m;j++)
            for(int k=0;k<=j-T;k++)///k枚举钓鱼时间,一开始错在把j-T 写成了 j-t[i],因为到第i个点必须要经过T的时间,所以钓鱼时间不能超过j-T
            {
                //if(k==m) printf("...%d
",i);
                int tmp=cal(i,k);
                if(dp[i][j]<dp[i-1][j-t[i]-k]+tmp)///k是从小到大推,这样我们就可以只要最大的dp中的最小的k
                {
                    dp[i][j]=dp[i-1][j-t[i]-k]+tmp;
                    path[i][j]=k;
                }
                //printf("tmp=%d
");
            }
        }
        int ans=0,a[30],pos=1;
        mem(a,0);
        for(int i=1;i<=n;i++)///从1开始递推,使前面的尽量大(后面0越多,前面呆的就越久)
            if(ans<dp[i][m]) ans=dp[i][m],pos=i;
        for(int i=pos,p=m;i>0;i--)
        {
            a[i]=path[i][p];
            p-=path[i][p]+t[i];
        }
        ///最后把剩余的时间全部加在第一个池塘,就能使字典序最大(剩余的时间包括时间到不了下一个而停留且池塘鱼数为0,那么也相当于在一号池塘停留再出发)
        int sum=0;
        for(int i=1;i<=n;i++) sum+=a[i];
        for(int i=2;i<=pos;i++) sum+=t[i];
        a[1]+=m-sum;
        if(test++) putchar('
');
        for(int i=1;i<=n;i++)
            printf("%d%s",5*a[i],i==n?"
":", ");
        printf("Number of fish expected: %d
",ans);
    }
    return 0;
}
/*
18
4
95 89 81 31 53 48 86 50 56 71 79 31 30 68 48 20 50 89
64 26 10 22 32 7 54 31 23 2 66 29 25 14 10 20 12 50
13 33 10 28 81 9 31 47 14 19 62 98 93 55 31 34 89
*/
原文地址:https://www.cnblogs.com/DeepJay/p/12025184.html