[kuangbin带你飞]专题十二 基础DP题解

Max Sum Plus Plus

HDU-1024
既然是动态规划,那么每个数字都有机会选上。每个数字,要不添在前一个连续区间构成数目不变的区间,要不就重新新开一个区间。我们可以写出状态转移方程: d p [ i ] [ j ] = m a x ( d p [ i ] [ j − 1 ] , m a x ( d p [ i − 1 ] [ m ] ( m > i ) ) ) dp[i][j] = max(dp[i][j-1] , max(dp[i-1][m](m>i))) dp[i][j]=max(dp[i][j1],max(dp[i1][m](m>i))),其中一维代表区间个数,二维代表此号元素。
有状态方程可知,这个算法的复杂度很高。我们仔细想一想,每个一维数组只跟上面一层有关系,所以用滚动数组来做,直接省掉了一维。再者, m m m的循环其实上一轮已经过了一次,所以用数组存一次就好了。
下面上代码:

//#include
#include
#include
#include
using namespace std;
const int MAX_N = 1e6+50;
const int inf = 0x3f3f3f3f;
int m,n;
int a[MAX_N];
int maxx[MAX_N];
int dp[MAX_N];
int main()
{
    while(scanf("%d%d",&m,&n)==2){
        dp[0] = 0;
        maxx[0] = 0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            maxx[i] = 0;
            dp[i] = 0;
        }
        int mmmax;
        for(int i=1;i<=m;i++){
            mmmax = -inf;
            for(int j=i;j<=n;j++){  ///j>=i,因为选的数字个数一定大于等于组的个数
                dp[j] = max(dp[j-1]+a[j],maxx[j-1]+a[j]);
                maxx[j-1] = mmmax;  ///因为mmmax存的是上一个数组的最值,到这个节点时已经要退一位了
                mmmax = max(mmmax,dp[j]);///所以maxx最后寄放到j-1的最大值
            }
        }
        ///printf("%d\n",dp[j]);错,因为最后第m组不一定会选dp[j],但mmmax
        ///肯定是在第m组中满足条件的最大的那一个
        printf("%d\n",mmmax);
    }
    return 0;
}

Ignatius and the Princess IV

HDU-1029
这个不算dp,更有点像思维题。一个奇数个数的数组,有一个数字出现次数大于等于(1+n)/2,找出这个数,那么可以这样写:选定一个数。遇到相同的数,cnt++,不同的数,cnt–,当cnt=0的时候,换数字,cnt++。最终的数字就是最后的num。
代码:

#include
#include
#include
#include
using namespace std;

#define N 1000000

int main()
{
    int n, num, cnt, ans;
    while(scanf("%d", &n)!=EOF)
    {
        cnt = 0;
        for(int i=0; i<n; i++)
        {
            scanf("%d", &num);
            if(cnt==0)
                ans = num, cnt++;
            else
            {
                if(num==ans)
                    cnt++;
                else
                    cnt--;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

Monkey and Banana

HDU-1069
将方块分成6分然后扔到选择序列,然后上01背包。自己没写出来,贴上kuangbin的代码。
代码:

#include
#include
const int MAXN=200;
using namespace std;
struct Block
{
    int x,y,high;
    int dp;//该箱子在最下面时的最大高度
}b[MAXN];

bool cmp(Block a,Block b)//用sort函数排序,先按x后按y升序
{
    if(a.x<b.x) return 1;
    else if(a.x==b.x&&a.y<b.y)  return 1;
    else return 0;
}
int main()
{
    int n,i,x,y,z,j,k;
    int iCase=0;
    while(scanf("%d",&n),n)
    {
        iCase++;
        k=0;
        while(n--)
        {
            scanf("%d%d%d",&x,&y,&z);
            //把给出的block放置的所有可能放进block[]中,这样就可以解决有无限块的问题
            if(x==y)
            {
                if(y==z)//三个相等,放一个就够了
                {
                    b[k].x=x;b[k].y=y;b[k].high=z;b[k].dp=b[k].high;k++;
                }
                else  //x==y!=z时三种放法
                {
                    b[k].x=x;b[k].y=y;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=z;b[k].y=y;b[k].high=x;b[k].dp=b[k].high;k++;
                    b[k].x=y;b[k].y=z;b[k].high=x;b[k].dp=b[k].high;k++;
                }
            }
            else
            {
                if(y==z)//三种放法
                {
                    b[k].x=x;b[k].y=y;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=y;b[k].y=x;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=y;b[k].y=z;b[k].high=x;b[k].dp=b[k].high;k++;
                }
                else if(x==z)
                {
                    b[k].x=x;b[k].y=y;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=y;b[k].y=x;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=x;b[k].y=z;b[k].high=y;b[k].dp=b[k].high;k++;
                }
                else//三个不等6种放法
                {
                    b[k].x=x;b[k].y=y;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=y;b[k].y=x;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=x;b[k].y=z;b[k].high=y;b[k].dp=b[k].high;k++;
                    b[k].x=z;b[k].y=x;b[k].high=y;b[k].dp=b[k].high;k++;
                    b[k].x=y;b[k].y=z;b[k].high=x;b[k].dp=b[k].high;k++;
                    b[k].x=z;b[k].y=y;b[k].high=x;b[k].dp=b[k].high;k++;
                }
            }
        }
        sort(b,b+k,cmp);
        int maxh=0;
        for(i=1;i<k;i++)
        {
            for(j=0;j<i;j++)
               if(b[i].x>b[j].x&&b[i].y>b[j].y)
                  b[i].dp=max(b[j].dp+b[i].high,b[i].dp);
            if(b[i].dp>maxh)maxh=b[i].dp;
        }
        printf("Case %d: maximum height = %d\n",iCase,maxh);
    }
    return 0;
}

							这里是分割线

题目尚且没有补完,仅先开此博客。

你可能感兴趣的:([kuangbin带你飞],简单及经典dp)