5.29翻车记录(bushi)四道各种背包问题

总体情况:

先看到第一题,很水,做完

觉得第二题稍微有些费劲,就先做三四题,

最后解决第二题

AC:T1和T4

T3:70

T4:91(题面有bug,没说是多组数据)

T1:最小乘车费用

假设某条街上每 一公里 就有一个公共汽车站,并且乘车费用如下表: 

公里数 1 2 3 4 5 6 7 8 9 10
费用 12 21 31 40 49 58 69 79 90 101 

而任意一辆汽车从不行驶超过 10 公里 。某人想行驶 n(1<=n<=100) 公里,假设他可以任意次换车,请你帮他找到一种乘车方案,使得总费用最小 

注意: 10 公里 的费用比 1 公里 小的情况是允许的。 

输入

共两行,第一行为 10 个不超过 200 的整数,依次表示行驶 1 ~ 10 公里的费用,相邻两数间用一个空格隔开;第二行为某人想要行驶的公里数。

输出

仅一行,包含一个整数,表示行使这么远所需要的最小费用。 

样例:

输入:12 21 31 40 49 58 69 79 90 101

    15

输出:147

很水的一维完全背包,把1-10公里看作物品,1-10为物品费用(体积),车费为价值(或者花费),求最小价值

注意要初始化2147483647

否则全是0

可选的开一下long long

#include<cstdio>
#include<algorithm>
using namespace std;
long long sav[1005] = {}, m, dp[1000005] = {};
int main()
{
    for(int i = 1;i <= 10;i++)
    {
        scanf("%lld", &sav[i]);    
    }
    scanf("%lld", &m);
    for(int i = 1;i <= m;i++)
    {
        dp[i] = 2147483647;    
    }
    for(int i = 1;i <= 10;i++)
    {
        for(int j = i;j <= m;j++)
        {
            dp[j] = min(dp[j],dp[j-i]+sav[i]);
        }
    }
    printf("%lld", dp[m]);
    return 0;    
}
/*
12  21 31 40 49 58  69 79 90 101
15
*/

 

T2:

质数和分解 

洛谷P2563

先预处理出素数表

在当作一维完全背包做

结束

#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
    long long int n, dp[10005] = {}, jud[205] = {}, cnt = 0, sav[2005] = {};
    dp[0] = 1;
    for(int i = 2;i <= 200;i++)
    {
        for(int j = 2;j <= 200;j++)
        {
            if(i * j <= 200)
            {
                jud[i*j] = 1;    
            }
        }
    }
    for(int i = 2;i <= 200;i++)
    {
        if(jud[i] == 0)
        {
            cnt++;
            sav[cnt] = i;
        }
    }
//    printf("%d", cnt);
//    scanf("%lld", &n);
    for(int i = 1;i <= cnt;i++)
    {
    /*    if(sav[i] > n)
        {
            break;    
        }*/
        for(int j = sav[i];j <= 200;j++)
        {
            dp[j] += dp[j-sav[i]];    
        }
    }
//    printf("%lld", dp[n]);
/*    for(int i = 2;i <= n;i++)
    {
        printf("%d\n", dp[i]);        
    }*/
    while(scanf("%d",&n)!=EOF)
        printf("%d\n",dp[n]);
    return 0;    
}

 

T3:

逃亡的准备:(hp厨狂喜)

 在《Harry Potter and the Deathly Hallows》中,Harry Potter他们一起逃亡,现在有许多的东西要放到赫敏的包里面,但是包的大小有限,所以我们只能够在里面放入非常重要的物品。现在给出该种物品的数量、体积、价值的数值,希望你能够算出怎样能使背包的价值最大的组合方式,并且输出这个数值,赫敏会非常感谢你。
【输入格式】
  第1行有2个整孰物品种数n和背包装载体积v;
  第2行到i+l行每行3个整数,为第i种物品的数量m、体积w、价值s。
【输出格式】
  仅包含一个整数,即为能拿到的最大的物品价值总和。
【输入样例】
  2 10
  3 4 3
  2 2 5
【输出样例】
  13
  样例说明:选第一种一个,第二种两个,结果为3×1+5×2=13。
【数据规模】
  对于30%的数据:1≤v≤500;1≤n≤2000;l≤m≤10;1≤w≤20;1≤s≤100;
  对于lOffl6的数据:1≤v≤500;1≤n≤2000;1≤m≤5000;1≤w≤20;1≤s≤100。

多重背包板子题

但是数据量偏大

第一次写的时候把板子的循环条件写错了,以后要注意这个问题

错误的写法:(没有把判断k*sav[i] <= j放在板子里或者直接break掉,导致计算量不必要的增加)

for(int i = 1;i <= n;i++)
{
    for(int j = v;j >= 0;j++)
    {
        for(int k = 1;k <= 第i件物品的种类;k++)
        {
            if(k * sav[i] <= j) 
            {
                dp[j] = max(dp[j],dp[j-k*savv[i]]+k*savw[i]);    
            }
        }
    }
}    

正确的写法(一):直接break;(因为如果前面的k*sav[i]超过j,后面的k*sav[i]也大于j)

for(int i = 1;i <= n;i++)
{
    for(int j = v;j >= 0;j++)
    {
        for(int k = 1;k <= 第i件物品的种类;k++)
        {
            if(k * sav[i] <= j) 
            {
                dp[j] = max(dp[j],dp[j-k*savv[i]]+k*savw[i]);    
            }
            else
            {
                break;    
            }
        }
    }
}    

正确的写法二:把判断写在最后一层循环里‘

for(int i = 1;i <= n;i++)
{
    for(int j = v;j >= 0;j++)
    {
        for(int k = 1;k <= 第i件物品的种类 && k * savv[i] <= j ;k++)
        {
            dp[j] = max(dp[j],dp[j-k*savv[i]]+k*savw[i]);    
        }
    }
}    

But,

在有写多重背包的题目中,会出现k * savv[i] > j 之后,后面的情况可能满足条件的情况。

因此,推荐第一种写法,如果出现上述特殊情况,就可以把break改成continue应对

总之,实际情况实际分析

 

PS:据某大佬说,判断的不同位置中有一种会导致数组下表溢出从而导致结果偏大,但我并没有发现

 

T3的AC代码

#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
    int v, n;
    long long dp[100005] = {};
    long long sav1[20005] = {}, sav2[20005] = {}, sav3[20005] = {};
    scanf("%d%d", &n, &v);
    for(int i = 1;i <= n;i++)
    {
        scanf("%lld%lld%lld", &sav1[i], &sav2[i], &sav3[i]);    
    }
    for(int i = 1;i <= n;i++)
    {
        for(int j = v;j >= 0;j--)
        {
            for(int k = 1;k <= sav1[i];k++)
            {
                if(k * sav2[i] <= j)
                {
                    dp[j] = max(dp[j],dp[j-k*sav2[i]] + sav3[i] * k);    
                }
                else
                {
                    break;    
                }//卡常多过30 
            }
        }
    }
    printf("%lld", dp[v]);
    return 0;    
}
/*
2 10
3 4 3 
2 2 5
*/

 

T4:暗黑游戏(csdn上有题目)

简单的二位费用多重背包

#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
    int n, p, r;
    long long savp[1005] = {}, savr[1005] = {}, savs[1005] = {}, sava[1005] = {};
    long long dp[205][205] = {};
    scanf("%d%d%d", &n, &p, &r);
    for(int i = 1;i <= n;i++)
    {
        scanf("%lld%lld%lld%lld", &savp[i], &savr[i], &savs[i], &sava[i]);    
    }
    for(int i = 1;i <= n;i++)
    {
        if(savs[i] != 0)
        {
            for(int j = p;j >= 0;j--)
            {
                for(int q = r;q >= 0;q--)
                {
                    for(int k = 1;k <= savs[i];k++)
                    {
                        if(k * savp[i] <= j && k * savr[i] <= q)
                        {
                            dp[j][q] = max(dp[j][q],dp[j-k*savp[i]][q-k*savr[i]] + sava[i] * k);    
                        }
                    }
                }
            }    
        }
        else
        {
            for(int j = savp[i];j <= p;j++)
            {
                for(int q = savr[i];q <= r;q++)
                {
                    dp[j][q] = max(dp[j][q],dp[j-savp[i]][q-savr[i]]+sava[i]);    
                }
            }    
        }
    }
    printf("%lld", dp[p][r]);
    return 0;    
}
/*
3 10 10
5 3 0 110
4 3 4 120
2 3 1 130
*/

 

 

qua+

posted @ 2021-05-29 18:00  Mint-hexagram  阅读(55)  评论(0编辑  收藏  举报