[hrbust acmbook] dp优化-改进状态表示

把n个数字,分成m组,每组的和不能大于t。分组必须按顺序

三维dp[i][j][k]: 显然状态太多,nmt为1000就爆了,i表示前i个数字,j表示分成j组,k表示最后一组已经放的数的和

关键是改进,改成二维

dp[i][j]:i表示前i个元素,j表示取j个数,dp数组是一个结构体数组,表示(x,y)

也就是说,dp数组存的是在前i个数中取j个数,需要的最少的组数和最后一组的已经放的数的和

好的放数方法,组数越少当然越好,组数一样的时候,y越小越好

这种思想很巧妙

UVA 473

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
int readint()
{
    char a;
    int num=0;
    a=getchar();
    while(!isdigit(a)) a=getchar();
    while(isdigit(a))
    {
        num=num*10+a-‘0‘;
        a=getchar();
    }
    return num;
}
struct point
{
    int x;
    int y;
};
point dp[1005][1005];
int a[1005];
int main()
{
    int kase;
    scanf("%d",&kase);
    for(int x=1;x<=kase;x++)
    {
        int n,t,m;
        scanf("%d%d%d",&n,&t,&m);
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<=n;j++)
            {
                dp[i][j].x=10000;
                dp[i][j].y=0;
            }
        }
        for(int i=0;i<=n;i++)
        {
            dp[i][0].x=1;
            dp[i][0].y=0;
        }
        for(int i=1;i<=n;i++) a[i]=readint();
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=i;j++)
            {
                dp[i][j]=dp[i-1][j];
                if(dp[i-1][j-1].y+a[i]<=t)
                {
                    if(dp[i-1][j-1].x<dp[i][j].x)
                    {
                        dp[i][j].x=dp[i-1][j-1].x;
                        dp[i][j].y=dp[i-1][j-1].y+a[i];
                    }
                    else if(dp[i-1][j-1].x==dp[i][j].x)
                    {
                        if(dp[i-1][j-1].y+a[i]<dp[i][j].y)
                        {
                            dp[i][j].y=dp[i-1][j-1].y+a[i];
                        }
                    }
                }
                else
                {
                    if(dp[i-1][j-1].x+1<dp[i][j].x)
                    {
                        dp[i][j].x=dp[i-1][j-1].x+1;
                        dp[i][j].y=a[i];
                    }
                    else if(dp[i-1][j-1].x+1==dp[i][j].x)
                    {
                        if(a[i]<dp[i][j].y)
                        {
                            dp[i][j].y=a[i];
                        }
                    }
                }
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            if(dp[n][i].x<=m) ans=i;
        }
        if(x!=1) printf("\n");
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-08-09 16:50:06

[hrbust acmbook] dp优化-改进状态表示的相关文章

LCIS tyvj1071 DP优化

思路: f[i][j]表示n1串第i个与n2串第j个且以j结尾的LCIS长度. 很好想的一个DP. 然后难点是优化.这道题也算是用到了DP优化的一个经典类型吧. 可以这样说,这类DP优化的起因是发现重复计算了很多状态,比如本题k的那层循环. 然后就可以用maxl标记搞一下,将O(n^3)变成O(n^2). #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> usi

dp优化1——sgq(单调队列)

该文是对dp的提高(并非是dp入门,dp入门者请先参考其他文章) 有时候dp的复杂度也有点大...会被卡. 这几次blog大多数会讲dp优化. 回归noip2017PJT4.(题目可以自己去百度).就是个很好的案例.那题是个二分套dp如果dp不优化复杂度O(n^2logn)还能拿60分(CCF太仁慈了,如果是我直接给10分). 正解加上个单调队列(其实是sliding window)O(nlogn) 我们发现,此类dp是这样的 状态i是由[l,r]转移过来的.且i在向右移动的过程中,[l,r]一

dp优化总结

dp优化总结 一.滚动数组 典型的空间优化. 这应该是最最普通的一个优化了吧.. 对于某些状态转移第i个只需要用到第i-1个状态时,就可以用滚动数组,把第一维用0/1表示. 拓展1: 当一个状态转移要用到前m个转移时,我们依然可以滚起来,把第一维按模m的值滚起来. 拓展2: 若每一个决策可以选任意次(在一定限度下),那么我们可以借鉴完全背包的思路,把决策一个一个累计起来,起到优化时间的作用.(例题:NOIP2013 飞扬的小鸟) 二.数据结构优化 1.单调队列 如果一个转移方程模型大致如下: \

POJ1787——背包DP(特定状态+回溯)——Charlie&#39;s Change

Description Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie drives a lot and so he often buys coffee at coffee vending machines at motorests. Charlie hates change. That is basically the setup of your next task. Your program will be given

常见的DP优化类型

常见的DP优化类型 1单调队列直接优化 如果a[i]单调增的话,显然可以用减单调队列直接存f[j]进行优化. 2斜率不等式 即实现转移方程中的i,j分离.b单调减,a单调增(可选). 令: 在队首,如果g[j,k]>=-a[i],那么j优于k,而且以后j也优于k,因此k可以重队列中直接删去.在队尾,如果x<y<z,且g[x,y]<=g[y,z],也就是说只要y优于x一定可以得出z优于y的,我们就删去y. 经过队尾的筛选,我们在队列中得到的是一个斜率递减的下凸包,每次寻找从上往下被-

hdu5009 离散化+dp+优化

西安网络赛C题.先对大数据离散化,dp优化 #include<iostream> //G++ #include<vector> #include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<queue> #include<cmath> using namespace std; const int maxn=512

loj6171/bzoj4899 记忆的轮廊(期望dp+优化)

题目: https://loj.ac/problem/6171 分析: 设dp[i][j]表示从第i个点出发(正确节点),还可以有j个存档点(在i点使用一个存档机会),走到终点n的期望步数 那么 a[i][k]表示i点为存档点,从i点走到k点(正确节点)的期望步数(中间没有其它存档点) 那么a[i][j]可以递推预处理出 其中g[v]表示从一个错误节点v开始走,期望走g[v]步会读档 解方程可以解出 s[j-1]就是点j-1出去的所有错误儿子的g[v]之和 那么接下来只要知道如何求g[v]就行了

poj1088 滑雪(dfs、dp优化)

#include <iostream> #include <map> #include <string> #include <cstdio> #include <sstream> #include <cstring> #include <vector> #include <cmath> #define N 110 int a,b,step=0; int anw=0; int moun[N][N]; int dp

基于Android官方AsyncListUtil优化改进RecyclerView分页加载机制(一)

基于Android官方AsyncListUtil优化改进RecyclerView分页加载机制(一) Android AsyncListUtil是Android官方提供的专为列表这样的数据更新加载提供的异步加载组件.基于AsyncListUtil组件,可以轻易实现常见的RecyclerView分页加载技术.AsyncListUtil技术涉及的细节比较繁复,因此我将分别写若干篇文章,分点.分解AsyncListUtil技术. 先给出一个可运行的例子,MainActivity.java: packag