Forth(背包!动态规则)

本文解析了几种经典的背包问题,包括01背包问题、完全背包问题等,并提供了详细的算法实现过程和示例输入输出,帮助读者深入理解背包问题的解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2852这对好基友他们在经历无数的艰难险阻后,终于找到了宝藏。无奈的是这一对好基友竟然是一样的粗心,又忘记了带一个大一点的包包,可惜啊、、选择又出现了啊、、
已知包的体积是v,每种宝贝只有一个,宝贝的体积是pi,价值是wi。求出这对粗心的基友可以最多带走价值多少的宝藏。
Input
输入数据有多组。
每组第一行有两个正整数n(n <= 10000)和v(v <= 10000)分别表示n种宝贝和包的体积。
接下来n行,每行有两个正整数vi, wi。
分别表示每种宝藏的体积vi (vi<=1000),价值wi(wi<=1000)。
Output
这对基友所能带走的最多的宝藏。
Example Input
5 10 
1 5
2 4
3 3
4 2
5 1
Example Output
14

  
01#include<iostream>
02#include<cstring>
03int max(int a,int b)
04{
05if(a>b)
06return a;
07else
08return b;
09}
10using namespace std;
11int main()
12{
13    int b[12000];
14    int n, x, pi[12000], mi[12000], i, j;
15    while(cin>>n>>x)
16    {
17        memset(b, 0, sizeof(b));
18        for(i = 0;i<n;i++)
19        {
20            cin>>pi[i]>>mi[i];
21        }
22        for(i=0;i<n;i++)
23        {
24            for(j=x;j>=pi[i];j--)
25            {
26                b[j] = max(b[j], b[j-pi[i]]+mi[i]);[意思是不买还是等于]
27            }
28        }
29        cout<<b[x]<<endl;
30        }
31        return 0;
32}
背包问题,公式应用。
  

3684 最近,智商频繁下线的 cyk 迷上了一个益智小游戏,每天都要玩到深夜,乐此不疲。

 

这个游戏的规则是这样的:

玩家控制一个游戏角色 cyk0 站在一个 n*m 的矩形格子地图上,每个格子都可以提供一定的智力值加成。

初始时 cyk0 位于左上角 (1, 1),游戏的目标是通过走若干步到达位于右下角 (n, m) 的智慧长者 cyk4 处。

沿途走到的格子可以增加相应的智力,到达终点时累积获得的智力就是游戏的得分。

普通玩家的角色每回合只能向右移动或向下移动一次,移动距离为一格。而 VIP 玩家可以在移动角色时选择是否使用主动技能「yk 大冲刺」。「yk 大冲刺」的效果是:使当前回合的移动距离扩大为地图尺寸的一半(向右移动时可以扩大为 m/2,向下移动时可以扩大为 n/2)。此技能是直接移动,中间经过的格子不累计智力值,而且不能越出地图边界,否则本次移动无效。VIP 技能每个回合只能施放一次。

 

虽然最近 cyk 购买了 VIP,不过他实在是太忙了,每天在实验室待到很晚,并没有太多时间去思考如何才能得到最高分。你能帮助他拿到最高分吗?

Input

第一行输入一个整数 T (0 < T <= 20),代表数据组数。

对于每组输入,首先输入一行,包含两个整数 n, m (0 < n, m <= 1000),表示地图的行数和列数,保证 n, m 不会是奇数。

接下来输入 n 行,每行 m 个以空格分隔的整数 ai (-10^7 <= ai <= 10^7),表示此格子上可提供的智力值。

Output

对于每组输入,输出一行,包含一个整数,代表 cyk 能得到的最高分。

Example Input
2
2 4
1 3 10 8
2 1 2 0
4 4
1 5 3 15
-3 -5 -4 -1
2 4 0 3
9 12 1 6

  
01#include<bits/stdc++.h>
02using namespace std;
03#define minlong -10100101010001
04long long ma[1100][1100],ai[1100][1100];
05int main()
06{
07int i,t,j,n,m,k;
08for(j=1;j<=1010;j++)
09{
10ma[0][j]=minlong;
11ma[j][0]=minlong;
12}
13ma[0][1]=ma[1][0]=0;
14cin>>t;
15for(i=1;i<=t;++i)
16{
17cin>>n>>m;
18for(j=1;j<=n;j++)
19for(k=1;k<=m;k++)
20cin>>ai[j][k];
21for(j=1;j<=n;j++)
22for(k=1;k<=m;k++)
23{
24ma[j][k]=max(ma[j-1][k],ma[j][k-1]);
25if(j>n/2) ma[j][k]=max(ma[j-n/2][k],ma[j][k]);
26if(k>m/2) ma[j][k]=max(ma[j][k-m/2],ma[j][k]);
27ma[j][k]=ma[j][k]+ai[j][k];
28}
29cout<<ma[n][m]<<endl;
30}
31return 0;
32}
33 
对每一回合的理解要正确,没一次都可以使用技能,但是横向跟纵向只能使用一次。并且最上边跟左边边界上的点都应该根据题目的具体要求设置上相应的值若全为正则可以设置为-1,若存在负数应当设定比最下界还小的数。因为边界是为了计算虚幻增加上的,所以后面的值求最大值之后都不会从边界中取数。
 
 
 
 
  
小P非常喜欢玩dota,不分昼夜的玩
,结果他连做梦也都是里面的画面,一天晚上小P刚躺下就做了一个神奇的梦。。。
不死族的巫妖王发工资拉,死亡骑士拿到一张N元的钞票(记住,只有一张钞票),为了防止自己在战斗中频繁的死掉,他决定给自己买一些道具,于是他来到了地精商店前.
死亡骑士:"我要买道具!"
地精商人:"我们这里有三种道具,血瓶150块一个,魔法药200块一个,无敌药水350块一个."
死亡骑士:"好的,给我一个血瓶."
说完他掏出那张N元的大钞递给地精商人.
地精商人:"我忘了提醒你了,我们这里没有找客人钱的习惯的,多的钱我们都当小费收了的,嘿嘿."
死亡骑士:"......"
死亡骑士想,与其把钱当小费送个他还不如自己多买一点道具,反正以后都要买的,早点买了放在家里也好,但是要尽量少让他赚小费.
现在死亡骑士感觉自己的智商不够用所以希望小P帮他计算一下,最少他要给地精商人多少小费.但是小P的智商可是出了名的“不忍直视”啊,聪明非凡的你所以你能帮帮他吗?
Input
输入数据的第一行是一个整数T(1<=T<=100),代表测试数据的数量.然后是T行测试数据,每个测试数据只包含一个正整数N(1<=N<=10000),N代表死亡骑士手中钞票的面值.
 
注意:地精商店只有题中描述的三种道具.
Output
 对于每组测试数据,请你输出死亡骑士最少要浪费多少钱给地精商人作为小费.
 
Example Input
2 
380 
200
Example Output
30 
0


  
01#include<bits/stdc++.h>
02using namespace std;
03int main()
04{
05int i,t,j,n,k,dp[10010];
06int w[3]={150,200,350};
07cin>>t;
08for(i=1;i<=t;++i)
09{
10cin>>n;
11memset(dp,0,sizeof(dp));
12for(j=0;j<3;j++)
13for(k=w[j];k<=n;k++)
14{
15dp[k]=max(dp[k],dp[k-w[j]]+w[j]);[完全背包问题:一定要明确从合法的钱数往后遍历跑循环,例如150,买了之后后面求最大值时只要不到300求出来的最大值依旧是150,之后再跑第二层,如果出现更大的则会覆盖。]
16}
17cout<<n-dp[n]<<endl;
18}
19return 0;
20}
多组背包问题。利用一维数组。
Problem Description
给定一个由n行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。   对于给定的由n行数字组成的数字三角形,计算从三角形的顶至底的路径经过的数字和的最大值。
Input
输入数据的第1行是数字三角形的行数n,1≤n≤100。接下来n行是数字三角形各行中的数字。所有数字在0..99之间。
Output
输出数据只有一个整数,表示计算出的最大值。
Example Input
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
Example Output
30
    
01#include <iostream>
02 
03using namespace std;
04 
05int main()
06{
07int n,i,j,D[101][101],a[101][101];
08cin>>n;
09for(i=1;i<=n;i++)
10for(j=1;j<=i;j++)
11cin>>D[i][j];
12for(j=1;j<=n;j++)
13a[n][j]=D[n][j];
14for(i=n-1;i>=1;i--)
15for(j=1;j<=i;j++)
16{
17if(a[i+1][j]>a[i+1][j+1])
18a[i][j]=a[i+1][j]+D[i][j];
19else
20a[i][j]=a[i+1][j+1]+D[i][j];
21}
22cout << a[1][1]<< endl;
23    return 0;
24}
动态规划就是记录每个点的状态。
状态转移方程,dp【i】=dp【i-1】+dp【i-2】;
dp[i][j]记录从第i行第j列出发到达底部得到的最大值,
图标问题的状态方程 dp【i】【j】=max(dp【i+1】【j】,dp【i+1【j+1】)+data【i】【j】; 大哭
背包问题:与贪心不同(贪心可以把价值排序从大到小买,但是背包是只能买整数个,例如10元钱,商品6,5,5,选择两个5元的要更优与买6元的)
1.
01背包问题:
i为个数,v为总容量;
已经装了i个物品装了j的容量dp[i][v]=max(dp[i-1][v],dp【i-1】【v-a【i】】+w【i】)关键是第i件物品放或不放;

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

从这个题目中可以看出,01背包的特点就是:每种物品仅有一件,可以选择放或不放。

其状态转移方程是:

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

对于这方方程其实并不难理解,方程之中,现在需要放置的是第i件物品,这件物品的体积是c[i],价值是w[i],因此f[i-1][v]代表的就是不将这件物品放入背包,而f[i-1][v-c[i]]+w[i]则是代表将第i件放入背包之后的总价值,比较两者的价值,得出最大的价值存入现在的背包之中。

多组输入。

对于每组输入,第一行有两个整数N,X(1 < = N < = 100,1 < = X < = 1000),分别表示哈士奇的数量和高数巨的钱数

对于每组数据,输出一个整数,表示高数巨最多可以获得的萌值,每组输出占一行

Example Input
2 10050 2060 403 10020 5520 3590 951 1020 50


#include<bits/stdc++.h>
02using namespace std;
03int main()
04{
05    int f[1200][1200],n,x,pi[1200],mi[1200],i,j;
06    while(cin>>n>>x)
07    {
08        memset(f,0,sizeof(f));
09        memset(pi,0,sizeof(pi));
10        memset(mi,0,sizeof(mi));
11        for(i=1; i<=n; i++)
12            cin>>pi[i]>>mi[i];
13        for(i = 1; i<=n; i++)
14        {
15            for(j = 0; j <=x; j++)
16            {
17                f[i][j] = f[i - 1][j];
18                if (j < pi[i]) continue;
19                f[i][j] = max(f[i-1][j], f[i-1][j-pi[i]]+mi[i]);
20            }
21        }
22        int ans = 0;
23//        for (int i = 1; i <= x; i++) ans = max(ans, f[n][i]);
24        cout<<f[n][x]<<endl;
25        }
26    return 0;
27}
28 
如果用二维背包需要J(容量)从 0 遍历;而且都每个数组都需要清空

最长上升子序列

Time Limit: 3000MS  Memory Limit: 65536KB
Problem Description
一个数的序列bi,当b 1 < b 2 < ... < b S的时候,我们称这个序列是上升的。对于给定的一个序列(a 1, a 2, ..., a N),我们可以得到一些上升的子序列(a i1, a i2, ..., a iK),这里1<= i 1 < i 2 < ... < i K <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8)。

你的任务,就是对于给定的序列,求出最长上升子序列的长度。
Input
输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。
Output
最长上升子序列的长度。
Example Input
7
1 7 3 5 9 4 8
Example Output
4

#include<iostream>
using namespace std;
int main()
{
int n,m,i,k,nmax,a[1010],maxlen[1010];
cin>>n;
for(i=1;i<=n;i++)
cin>>a[i];
maxlen[1]=1;
for(k=2;k<=n;k++)
{
m=0;
for(i=1;i<k;i++)
{
if(a[k]>a[i]&&m<maxlen[i])
m=maxlen[i];
maxlen[k]=m+1;
}
}
nmax=-1;
for(i=1;i<=n;i++)
if(nmax<maxlen[i])
nmax=maxlen[i];
cout<<nmax;
return 0;
}

最长公共子序列问题

Time Limit: 1000MS  Memory Limit: 65536KB
Problem Description
 给定两个序列X=
Input
输入数据有多组,每组有两行 ,每行为一个长度不超过500的字符串(输入全是大写英文字母(A,Z)),表示序列X和Y。
Output
每组输出一行,表示所求得的最长公共子序列的长度,若不存在公共子序列,则输出0。
Example Input
ABCBDAB
BDCABA
Example Output
4


01#include<bits/stdc++.h>
02using namespace std;
03int main()
04{
05int j,i,len1,len2,c[500][500];
06char x[500],y[500];
07while(cin>>x>>y)
08{
09len1=strlen(x);
10len2=strlen(y);
11for(i=0;i<=len1;i++)
12c[i][0]=0;
13for(j=0;j<=len2;j++)
14c[0][j]=0;
15for(i=1;i<=len1;i++)
16for(j=1;j<=len2;j++)
17{
18if(x[i-1]==y[j-1])
19c[i][j]=c[i-1][j-1]+1;
20else
21c[i][j]=max(c[i-1][j],c[i][j-1]);
22}
23cout<<c[len1][len2]<<endl;
24}
25return 0;
26}
27 
一个建立在二维数组的行坐标上,另一个建立在二维数组的列坐标上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值