dp复习

#1: 【dp开始】数字三角形

题目描述

观察下面的数字金字塔。

写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

      7 
    3   8 
     8   1   0 
  2   7   4   4 
   4   5   2   6   5 

在上面的样例中,从7 到 3 到 8 到 7 到 5 的路径产生了最大

输入格式

第一个行包含 R(1<= R<=1000) ,表示行的数目。

后面每行为这个数字金字塔特定行包含的整数。

所有的被供应的整数是非负的且不大于100。

输出格式

单独的一行,包含那个可能得到的最大的和。

样例数据

input

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

output

30

数据规模与约定

usaco1.5.1

时间限制:1s1 \text {s}1s

空间限制:256MB256 \text {MB}256MB
这题呢有种非常暴力的解法,就是两重循环,每次a[i][j]都由上面两个与其接近的数的最大值。最后再对a[r][i]取max。
Code:

#include<bits/stdc++.h>
using namespace std;
#define f(a,b,c)  for(int c=a;c<=b;c++)
const int twx=1000+10;
int a[twx][twx];
int r;
int sum;
void init()
{
    cin>>r;
    f(1,r,i)
    {
        f(1,i,j)
        {
            cin>>a[i][j];
        }
    }
}
void work()
{
    f(1,r,i)
    {
        f(1,i,j)
        {
            a[i][j]=a[i][j]+max(a[i-1][j],a[i-1][j-1]);
        }
    }
}
void print()
{
    f(1,r,i)
    {
        sum=max(a[r][i],sum);
    }
    cout<<sum;
}
int main()
{
    //freopen("numtri.in","r",stdin);
    //freopen("numtri.out","w",stdout);
    init();
    work();
    print();
}

#2: 导弹拦截

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭,由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹的枚数和导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,每个数据之间有一个空格),计算这套系统最多能拦截多少导弹?

如果要拦截所有导弹最少要配备多少套这种导弹拦截系统?

输入格式

第一行数字n表示n个导弹(n<=200)
第二行n个数字,表示n个导弹的高度

输出格式

一个整数,表示最多能拦截的导弹数

一个整数,表示要拦截所有导弹最少要配备的系统数

样例数据

input

8
389  207  155  300  299  170  158  65  

output

6
2

数据规模与约定

时间限制:1s1 \text {s}1s

空间限制:256MB256 \text {MB}256MB
本题第一问是最长不下降子序列问题,十分经典。第二问是贪心,每颗导弹来袭时,使用能拦截这颗导弹的防御系统中上一次拦截导弹高度最低的那一套来拦截。若不存在符合这一条件的系统,则使用一套新的系统。
Code:

#include<bits/stdc++.h>
using namespace std;
#define f(a,b,c) for(int c=a;c<=b;c++)
#define so1(a,n,mycmp) sort(a+1,a+n+1,mycmp);
#define so2(a,n) sort(a+1,a+n+1);
#define ll long long
#define in cin
#define out cout
const int twx=10000+100;
int n;
int a[twx]={};
int f[twx]={};
int h[twx]={};
int ans1=-1e5;
int ans2=1;
void init()
{
    in>>n;
    f(1,n,i)
    {
        in>>a[i];
    }
}
void work()
{
    f[1]=1;
    f(2,n,i)
    {
        f(1,i-1,j)
        {
            if(a[i]<=a[j]&&f[j]>f[i])
            {
                f[i]=f[j];
            }
        }
        f[i]++;
        if(f[i]>ans1)
        {
            ans1=f[i];
        }
    }
    h[1]=a[1];
    f(2,n,i)
    {
        f(1,ans2,j)
        {
            so2(h,ans2)
            if(h[ans2]<a[i])
            {
                ans2++;
                h[ans2]=a[i];
                break;
            }
            if(h[j]>=a[i])
            {
                h[j]=a[i];
                break;
            }
        }
    }
}
void print()
{
    out<<ans1<<endl<<ans2;
}
int main()
{
    //freopen("missile.in","r",stdin);
    //freopen("missile.out","w",stdout);
    init();
    work();
    print();
    return 0;
}

#3: lis模板题

题目描述

NNN个整数,输出这NNN个整数的最长上升序列、最长下降序列、最长不上升序列和最长不下降序列。

输入格式

第一行,仅有一个数NNNN&lt;=700000N&lt;=700000N<=700000
第二行,有NNN个整数。 $-109<=每个数<=109 $

输出格式

第一行,输出最长上升序列长度。

第二行,输出最长下降序列长度。

第三行,输出最长不上升序列长度。

第四行,输出最长不下降序列长度。

样例数据

input

10
1 3 0 8 6 2 3 1 4 2

output

4
4
4
4

数据规模与约定

数据生成由 zqc,heaonan,zhouhang 等人对拍而成

时间限制:1s1 \text {s}1s

空间限制:256MB256 \text {MB}256MB
本题呢最主要的是使用log级的算法(二分吧 毕竟700000 O(n^2)的算法也会超),四个操作有着极大打相似度,请自行注意。
Code:

#include<bits/stdc++.h>
using namespace std;
#define f(a,b,c) for(int c=a;c<=b;c++)
#define so1(a,n,mycmp) sort(a+1,a+n+1,mycmp);
#define so2(a,n) sort(a+1,a+n+1);
#define ll long long
#define in cin
#define out cout
const int twx=700000+100;
int n;
ll a[twx];
ll b[twx]; 
ll s1,s2,s3,s4;
void clean()
{
    memset(b,0,sizeof(b));
}
void init()
{
    in>>n;
    f(1,n,i)
    {
        scanf("%lld",&a[i]);
    }
}
void work_1()//最长上升序列长度
{
    clean();
    s1=0;
    ll pos;
    b[0]=-1e10;
    f(1,n,i)
    {
        if(a[i]>b[s1])
        {
            b[++s1]=a[i];
        }
        else
        {
            ll Left=1;
            ll Right=s1;
            ll Mid;
            while(Left+1<Right)
            {
                Mid=(Left+Right)/2;
                if(a[i]>b[Mid])
                {
                    Left=Mid;
                }
                else
                {
                    Right=Mid;
                }
            }
            if(a[i]>b[Left])
            {
                pos=Right;
            }
            else
            {
                pos=Left;
            }
            b[pos]=min(b[pos],a[i]);
        }
    }
}
void work_2()//最长下降序列
{
    clean();
    s2=0;
    ll pos;
    b[0]=1e10;
    f(1,n,i)
    {
        if(a[i]<b[s2])
        {
            b[++s2]=a[i];
        }
        else
        {
            ll Left=1;
            ll Right=s2;
            ll Mid;
            while(Left+1<Right)
            {
                Mid=(Left+Right)/2;
                if(a[i]<b[Mid])
                {
                    Left=Mid;
                }
                else
                {
                    Right=Mid;
                }
            }
            if(a[i]<b[Left])
            {
                pos=Right;
            }
            else
            {
                pos=Left;
            }
            b[pos]=max(b[pos],a[i]);
        }
    }
}
void work_3()//最长不上升序列
{
    clean();
    s3=0;
    ll pos;
    b[0]=1e10;
    f(1,n,i)
    {
        if(a[i]<=b[s3])
        {
            b[++s3]=a[i];
        }
        else
        {
            ll Left=1;
            ll Right=s3;
            ll Mid;
            while(Left+1<Right)
            {
                Mid=(Left+Right)/2;
                if(a[i]<=b[Mid])
                {
                    Left=Mid;
                }
                else
                {
                    Right=Mid;
                }
            }
            if(a[i]<=b[Left])
            {
                pos=Right;
            }
            else
            {
                pos=Left;
            }
            b[pos]=max(b[pos],a[i]);
        }
    }
}
void work_4()// 最长不下降序列
{
    clean();
    s4=0;
    ll pos;
    b[0]=-1e10;
    f(1,n,i)
    {
        if(a[i]>=b[s4])
        {
            b[++s4]=a[i];
        }
        else
        {
            ll Left=1;
            ll Right=s4;
            ll Mid;
            while(Left+1<Right)
            {
                Mid=(Left+Right)/2;
                if(a[i]>=b[Mid])
                {
                    Left=Mid;
                }
                else
                {
                    Right=Mid;
                }
            }
            if(a[i]>=b[Left])
            {
                pos=Right;
            }
            else
            {
                pos=Left;
            }
            b[pos]=min(b[pos],a[i]);
        }
    }
}
void print()
{
    out<<s1<<endl<<s2<<endl<<s3<<endl<<s4;
}
int main()
{
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    init();
    work_1();
    work_2();
    work_3();
    work_4();
    print();
    return 0;
}

#4: 【背包】采药

题目描述

宁智贤是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。

医师为了判断他的资质,给他出了一个难题。

医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。

如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是宁智贤,你能完成这个任务吗?

输入格式

输入的第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式

输出包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

样例数据

input

70 3
71 100
69 1
1 2

output

3

数据规模与约定

时间限制:1s1 \text {s}1s

空间限制:256MB256 \text {MB}256MB
这是一道很裸的0/1背包的题目,核心代码就是asd[j]=max(asd[j],asd[j-a[i].shijian]+a[i].jiazhi) 这不就是0/1背包吗???
Code:

#include<bits/stdc++.h>
using namespace std;
#define f(a,b,c) for(int c=a;c<=b;c++)
#define so1(a,n,mycmp) sort(a+1,a+n+1,mycmp);
#define so2(a,n) sort(a+1,a+n+1);
#define ll long long
#define in cin
#define out cout
const int twx=10000+100;
int t,m;
struct LV
{
    int shijian;
    int jiazhi;
}a[twx];
int asd[twx];
void init()
{
    in>>t>>m;
    f(1,m,i)
    {
        in>>a[i].shijian>>a[i].jiazhi;
    }
}
void work()
{
    f(1,m,i)
    {
        for(int j=t;j>=a[i].shijian;j--)
        {
            asd[j]=max(asd[j],asd[j-a[i].shijian]+a[i].jiazhi);
        }
    }
}
void print()
{
    out<<asd[t];
}
int main()
{
    //freopen("input.in","r",stdin);
    //freopen("output.out","w",stdout);
    init();
    work();
    print();
    return 0;
}

#5: 背包的第k优解

题目描述

DD 和好朋友们要去爬山啦!他们一共有 K 个人,每个人都会背一个包。这些包的容量是相同的,都是 V。可以装进背包里的一共有 N 种物品,每种物品都有给定的体积和价值。

在 DD 看来,合理的背包安排方案是这样的:

  1. 每个人背包里装的物品的总体积恰等于包的容量。

  2. 每个包里的每种物品最多只有一件,但两个不同的包中可以存在相同的物品。

  3. 任意两个人,他们包里的物品清单不能完全相同。

在满足以上要求的前提下,所有包里的所有物品的总价值最大是多少呢?

输入格式

第一行有三个整数:K、V、N。

第二行开始的 N 行,每行有两个整数,分别代表这件物品的体积和价值。

输出格式

只需输出一个整数,即在满足以上要求的前提下所有物品的总价值的最大值。

样例数据

input

2 10 5
3 12
7 20
2 4
5 6
1 1

output

57

样例说明

一种可以得到最优解的方案是:第一个人背体积为 7、2、1 的三种物品,价值为 25。第二个人背体积为 3、7 的两种物品,价值为 32。总价值 57。

数据规模与约定

保证总人数 K<=50。 每个背包的容量 V<=5000。 物品种类数 N<=200。

其它正整数都不超过 5000。 输入数据保证存在满足要求的方案。

时间限制:1s1 \text {s}1s

空间限制:256MB256 \text {MB}256MB
本题一开始先将初值设为负无穷,代表不存在解,在原先完全背包的基础上加上一维,设asd[j][k]表示体积为j是第k优解的值。先令asd[0][1]=0。让t往上加,这个t是否增加取决于当前的最优值的决定取值,设yusuan1和yusuan2如果要这个物品就是yusuan2++,不要就是yusuan1++
Code:

///                   _ooOoo_
///                  o8888888o
///                  88" . "88
///                  (| -_- |)
///                  O\  =  /O
///               ____/`---'\____
///             .'  \\|     |//  `.
///            /  \\|||  :  |||//  \
///           /  _||||| -:- |||||-  \
///           |   | \\\  -  /// |   |
///           | \_|  ''\---/''  |   |
///           \  .-\__  `-`  ___/-. /
///         ___`. .'  /--.--\  `. . __
///      ."" '<  `.___\_<|>_/___.'  >'"".
///     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
///     \  \ `-.   \_ __\ /__ _/   .-` /  /
///======`-.____`-.___\_____/___.-`____.-'======
///                   `=---='
///^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
///
///         佛祖保佑       永无BUG
///
///  本模块已经经过ycy开光处理,绝无可能再产生bug
///
///=============================================
///     へ     /|
///  /\7    ∠_/
///  / │   / /
/// │ Z _,< /   /`ヽ
/// │     ヽ   /  〉
///  Y     `  /  /
/// ?● ? ●  ??〈  /
/// ()  へ    | \〈
///  >? ?_  ィ  │ //
///  / へ   / ?<| \\
///  ヽ_?  (_/  │//
///  7       |/
///  >―r ̄ ̄`?―_
#include<bits/stdc++.h>
using namespace std;
#define f(a,b,c) for(int c=a;c<=b;c++)
#define so1(a,n,mycmp) sort(a+1,a+n+1,mycmp);
#define so2(a,n) sort(a+1,a+n+1);
#define ll long long
#define in cin
#define out cout
const int twx=200+100;
int k,v,n;
int weight[twx],value[twx];
int a[twx*20],b[twx*20],asd[twx*20][twx*20];
int ans=0;
int yusuan1,yusuan2;
int t;
void init()
{
    in>>k>>v>>n;
    f(1,n,i)
    {
        in>>weight[i]>>value[i];
    }
}
void work()
{
    memset(asd,-10,sizeof(asd));
    asd[0][1]=0;
    for(int i=n;i>=1;i--)
    {
        for(int j=v;j>=weight[i];j--)
        {
            yusuan1=1;
            yusuan2=1;
            f(1,k,l)
            {
                a[l]=asd[j][l];
                b[l]=asd[j-weight[i]][l]+value[i];
            }
            t=0;
            while(t<k)
            {
                if(a[yusuan1]>b[yusuan2]) 
                {
                    t++;
                    asd[j][t]=a[yusuan1];
                    yusuan1++;
                }
                else 
                {
                    t++; 
                    asd[j][t]=b[yusuan2]; 
                    yusuan2++;
                }
            }
        }
    }
    f(1,k,i)
    {
        ans+=asd[v][i];
    }
}
void print()
{
    out<<ans;
}
int main()
{
    //freopen("bags.in","r",stdin);
    //freopen("bags.out","w",stdout);
    init();
    work();
    print();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值