• 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
    */
    
  • 相关阅读:
    c#判断输入的是不是数字
    params 关键字载入空值的陷阱
    拆箱陷阱
    接口的概念和声明
    数据库
    ios 纵向的UISlider
    微信小程序学习网站
    Spark RDD(2)
    SparkSql
    廖雪峰老师学习网站
  • 原文地址:https://www.cnblogs.com/DeepJay/p/12025184.html
Copyright © 2020-2023  润新知