2020年4月第三周

学习内容

本周继续学习了背包问题,这里简单总结一下背包问题的梗概和知识点;

背包问题大概分为:01背包、完全背包、多重背包、混合背包(听说还有双重背包,简单来说就是在背包V体积基础上多了一重M重量限制,在做题中需要对数据开二维dp数组)。

背包在初始化前一定要看好题目要求,是否要求恰好装满,如果要求,则f[0]=0;其他为-∞;否则全部为零(在这个小细节栽了好几次坑,下次一定注意orz)

01背包

有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。

每种物品有且只有一件。

f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

根据状态转移方程的实际意义可降维优化:

完全背包

每种物品都有无穷件可用

for i=1...N

    for i=0...V    //注意循环顺序

        f[v]=max(f[v],f[v-c[i]]+w[i]);

问题解决

题目描述
一个旅行者有一个最多能装 M 公斤的背包,现在有 n 件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn,求旅行者能获得最大总价值。

输入
第一行:两个整数,M(背包容量,M≤200)和N(物品数量,N≤30);

第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。

输出
仅一行,一个数,表示最大总价值。

输入样例
10 4
2 1
3 3
4 5
7 9
输出样例
12

本题为单纯的01背包问题,在今天讲课的时候讲到了用函数来求解,稍微试了一下

函数部分套用最简单的f[v]=max(f[v],f[v-c[i]]+w[i]);

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define MAX 2005
using namespace std;
#define N 1001
int m,n;
int w[N],c[N],f[N];
void ZeroOnePack(int cost,int weight)
{
    for(int v=m;v>=weight;v--)
        {
            f[v]=max(f[v],f[v-weight]+cost);
            //cout<<"["<>m>>n;
    for(int i=1;i<=n;i++)
        cin>>w[i]>>c[i];
    for(int i=1;i<=n;i++)
        ZeroOnePack(c[i],w[i]);
    cout<

L-L

在Mars星球上,每个Mars人都随身佩带着一串能量项链。在项链上有N颗能量珠。能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。因为只有这样,通过吸盘(吸盘是Mars人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。如果前一颗能量珠的头标记为m,尾标记为r,后一颗能量珠的头标记为r,尾标记为n,则聚合后释放的能量为(Mars单位),新产生的珠子的头标记为m,尾标记为n。
需要时,Mars人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。
例如:设N=4,4颗珠子的头标记与尾标记依次为(2,3) (3,5) (5,10) (10,2)。我们用记号⊕表示两颗珠子的聚合操作,(j⊕k)表示第j,k两颗珠子聚合后所释放的能量。则第4、1两颗珠子聚合后释放的能量为:
(4⊕1)=10*2*3=60。
这一串项链可以得到最优值的一个聚合顺序所释放的总能量为
((4⊕1)⊕2)⊕3)=10*2*3+10*3*5+10*5*10=710。

有多组测试数据。

对于每组测试数据,输入的第一行是一个正整数N(4≤N≤100),表示项链上珠子的个数。第二行是N个用空格隔开的正整数,所有的数均不超过1000。第i个数为第i颗珠子的头标记(1≤i≤N),当i

至于珠子的顺序,你可以这样确定:将项链放到桌面上,不要出现交叉,随意指定第一颗珠子,然后按顺时针方向确定其他珠子的顺序。

    处理到文件结束。

对于每组测试数据,输出只有一行,是一个正整数E(E≤2.1*109),为一个最优聚合顺序所释放的总能量。

Sample Input

4
2 3 5 10

Sample Output

710

区间DP,思路:石子合并之环形合并,考虑将珠子剪开,将原有的序列变为两倍,例如:1,2,3,4 可以展成 1,2,3,4,3,2,1,用 dp[i][j] 表示合并区间 i 到 j 的最大能量,第一重循环表示珠子分组的终点,第二重循环的表示从珠子分组的起点 ,第三重循环表示截断的点,注意多组数据的输入。令f[i][j]表示合并ij的珠子的最大能量。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define LL long long
#define MAX 2005
using namespace std;
#define N 201

LL a[N];
LL dp[N][N];
int main()
{
    int n;
    while(cin>>n)
    {
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            a[i+n]=a[i];
        }

        memset(dp,0,sizeof(dp));
        for(int len=2;len<=n;len++)
        {
            for(int i=1;i+len-1<=2*n;i++)
            {
                int j=len+i-1;
                for(int k=i;k

A-A

Gappu has a very busy weekend ahead of him. Because, next weekend is Halloween, and he is planning to attend as many parties as he can. Since it's Halloween, these parties are all costume parties, Gappu always selects his costumes in such a way that it blends with his friends, that is, when he is attending the party, arranged by his comic-book-fan friends, he will go with the costume of Superman, but when the party is arranged contest-buddies, he would go with the costume of 'Chinese Postman'.

Since he is going to attend a number of parties on the Halloween night, and wear costumes accordingly, he will be changing his costumes a number of times. So, to make things a little easier, he may put on costumes one over another (that is he may wear the uniform for the postman, over the superman costume). Before each party he can take off some of the costumes, or wear a new one. That is, if he is wearing the Postman uniform over the Superman costume, and wants to go to a party in Superman costume, he can take off the Postman uniform, or he can wear a new Superman uniform. But, keep in mind that, Gappu doesn't like to wear dresses without cleaning them first, so, after taking off the Postman uniform, he cannot use that again in the Halloween night, if he needs the Postman costume again, he will have to use a new one. He can take off any number of costumes, and if he takes off k of the costumes, that will be the last k ones (e.g. if he wears costume A before costume B, to take off A, first he has to remove B).

Given the parties and the costumes, find the minimum number of costumes Gappu will need in the Halloween night.

 输入

Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case starts with a line containing an integer N (1 ≤ N ≤ 100) denoting the number of parties. Next line contains N integers, where the ith integer ci (1 ≤ ci ≤ 100) denotes the costume he will be wearing in party i. He will attend party 1 first, then party 2, and so on.

输出

For each case, print the case number and the minimum number of required costumes.

Sample Input

2
4
1 2 1 2
7
1 2 1 1 3 2 1

Sample Output

Case 1: 3

Case 2: 4

给你n天需要穿的衣服的样式,每次可以套着穿衣服,就是可以先穿a再穿b,把b脱掉了最外面就是a了。,脱掉的衣服就不能再

用了(可以再穿,但算cost),问至少总共有几件衣服才能参加所有宴会。

 

很明显为区间dp,dp[i][j]表示i~j天所需的最小数量。

考虑第j天穿不穿,如果穿的话那么 dp[i][j]=dp[i][j-1]+1;

如果不穿的话,那么需要有一个 k (i<=k

dp[i][j]=dp[i][k]+dp[k+1][j-1];

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define LL long long
#define MAXN 100+7
using namespace std;
#define N 201

int n,m;
int num[MAXN];
int dp[MAXN][MAXN];
int main()
{
    int t;
    scanf("%d",&t);
    int ca = 0;
    while(t--)
    {
        scanf("%d",&n);
        for(int i = 1 ; i <= n ; ++i)scanf("%d",&num[i]);
        for(int i = n ; i >= 1; --i)
            for(int j = i ; j <= n ;++j)
        {
            dp[i][j] = dp[i+1][j] + 1;
            for(int k = i+1 ; k <= j ; ++k)
            {
                if(num[k] == num[i])dp[i][j] = min(dp[i][j],dp[i+1][k-1] + dp[k][j]);
            }
        }
        printf("Case %d: %d\n",++ca,dp[1][n]);
    }
}

 想法总结

说实话我感觉背包和区间DP比之前学的线性DP要简单一丝,可能是孤陋寡闻见题不够=-=下周开始要参加CF。。说实话心里没底,希望能加强一下自己的思维吧,现在讲课时的一些东西都不一定跟上,需要课下再自己搞一遍QAQ

你可能感兴趣的:(笔记)