P1616 疯狂的采药
#include<iostream>
using namespace std;
int main(){
long long w1[100000005];int w2[10005];
long long ans[10000005];
long long t;int m;cin>>t>>m;
for(int i=1;i<=m;i++)cin>>w1[i]>>w2[i];
for(int i=1;i<=m;i++){
for(long long j=w1[i];j<=t;j++){
ans[j]=max(ans[j],ans[j-w1[i]]+w2[i]);
}
}
cout<<ans[t];
return 0;
}
P1833 樱花
#include<iostream>
#include<cstdio>
using namespace std;
//存状态的答案,经过二进制拆分后的美学值,经过二进制拆分的耗时,经过二进制拆分后的物品数量
int ans[10000], c[100000], t[100000], rn = 0;
//存某个物品是否是完全背包(拆分后的物品)
bool infinity[100000];
//添加一个物品(用于拆分物品)
//参数:美学值,耗时,可观看次数(0是无限次,1是一次,拆分后不存在其他的次数)
void add(int ac, int at, int ap)
{
rn++;
c[rn] = ac;
t[rn] = at;
infinity[rn] = ap == 0;
}
int main()
{
//n、现在时间的时、现在时间的分、上学时间的时、上学时间的分、现在到上学的时间
int n, sh, sm, eh, em, tt;
scanf("%d:%d %d:%d %d", &sh, &sm, &eh, &em, &n);
//计算现在到上学的时间
tt = em - sm + (eh - sh) * 60;
//读
for (int i = 1; i <= n; i++)
{
//耗时,美学值,次数
int ti, ci, pi;
cin >> ti >> ci >> pi;
//如果时多重背包
if (pi > 1)
{
//二进制拆分
int temp = 1;
//拆分成数量为 1, 2, 2 ^ 2, ..., 2 ^ (n - 1) 的部分
while (temp * 2 - 1 <= pi)
{
add(temp * ci, temp * ti, 1);
temp *= 2;
}
//超过 2 ^ n - 1 的部分
int left = pi - temp + 1;
if (left != 0)
{
add(left * ci, left * ti, 1);
}
}
//01背包或者完全背包
else
{
add(ci, ti, pi);
}
}
for (int i = 1; i <= rn; i++)
{
//完全背包
if (infinity[i])
{
//完全背包模板
for (int j = t[i]; j <= tt; j++)
{
ans[j] = max(ans[j], ans[j - t[i]] + c[i]);
}
}
//01背包
else
{
//01背包模板
for (int j = tt; j >= t[i]; j--)
{
ans[j] = max(ans[j], ans[j - t[i]] + c[i]);
}
}
}
cout << ans[tt] << endl;
return 0;
}
P1077 [NOIP2012 普及组] 摆花
dfs写法:
#include<bits/stdc++.h>
using namespace std;
const int maxn=105, mod = 1000007;
int n, m, a[maxn];
int dfs(int x,int y){//x种花y盆
if(y>m)return 0;
if(y==m)return 1;
if(x>n)return 0;
int ans=0;
for(int i=0;i<=a[x];i++)
ans+=dfs(x+1,y+i);
return ans;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
cout<<dfs(1,0);
return 0;
}
动态规划:
#include<bits/stdc++.h>
using namespace std;
const int maxn=105, mod = 1000007;
int n, m, a[maxn], f[maxn][maxn];
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++) cin>>a[i];
f[0][0] = 1;
for(int i=1; i<=n; i++){
for(int j=0; j<=m; j++){
for(int k=0; k<=min(j, a[i]); k++){
f[i][j] = (f[i][j] + f[i-1][j-k])%mod;
}
}
}
cout<<f[n][m]<<endl;
return 0;
}
P1064 [NOIP2006 提高组] 金明的预算方案
#include<iostream>
using namespace std;
//最大的钱的数量、最大的物品数
constexpr int maxN = 3.2e4 + 5, maxM = 60 + 5;
//钱的数量、物品数、存每组物品的价值、存每组物品的重要度、存放每个状态的答案
int n, m, v[maxM][3], w[maxM][3], ans[maxN];
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int tv, tp, tq;
cin >> tv >> tp >> tq;
//是主件
if (tq == 0)
{
v[i][0] = tv;
w[i][0] = tp;
}
//是附件
else
{
//是第一个附件
if (v[tq][1] == 0)
{
v[tq][1] = tv;
w[tq][1] = tp;
}
//是第二个附件
else
{
v[tq][2] = tv;
w[tq][2] = tp;
}
}
}
//01背包
for (int i = 1; i <= m; i++)
{
//只对存有物品组的做内层循环
if (v[i][0] != 0)
{
for (int j = n; j >= v[i][0]; j--)
{
//不选或只选主件
ans[j] = max(ans[j], ans[j - v[i][0]] + w[i][0] * v[i][0]);
//能选主件+1号附件时
if (j >= v[i][0] + v[i][1])
{
ans[j] = max(ans[j], ans[j - v[i][0] - v[i][1]] + w[i][0] * v[i][0] + w[i][1] * v[i][1]);
}
//能选主件+2号附件时
if (j >= v[i][0] + v[i][2])
{
ans[j] = max(ans[j], ans[j - v[i][0] - v[i][2]] + w[i][0] * v[i][0] + w[i][2] * v[i][2]);
}
//能选主件+所有附件时
if (j >= v[i][0] + v[i][1] + v[i][2])
{
ans[j] = max(ans[j], ans[j - v[i][0] - v[i][2] - v[i][1]] + w[i][0] * v[i][0] + w[i][2] * v[i][2] + w[i][1] * v[i][1]);
}
}
}
}
cout << ans[n] << endl;
return 0;
}