C - 这不是背包问题
Description
后藤一里在学习求约数时,想到了下面一个简单的题目,希望你来解答一下。
给定一个数字 N,请你选取求和后不超过 N 的若干个不同的正整数,使得选取后的所有数的约数之和(这里的约数不包括 1 和数字本身)最大,请你输出这个最大的和。
Input
第一行输入一个正整数 N(1≤N≤2000)
Output
输出最大和。
Samples
Input 10 11 Output 7 7
Hint
样例 1 和 2,都是选取数字 4 和 6,求和式子为 (2)+(2+3)=7
问题分析:首先这是一个有标明范围的问题,我们可以先把2~2000的约数存到数组里,便于取用,然后就是经典的背包模型改。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
const int P=1e4+4;
int w[N];//所含的“价值”
int c[N];//占用的“体积”
int f[P][P];
signed main()
{
int n, V;
while(cin >> n >> V ){
for (int i = 1; i <= n; i++)
cin >> c[i] >> w[i];
for(int i = 1; i <= n; i++)
{
for(int j = V; j >= 0; j--){
f[i&1][j]=f[(i-1)&1][j];
if (j >= c[i])f[i&1][j] = max(f[i&1][j], f[(i-1)&1][j - c[i]] + w[i]);
}
} cout<<f[n][V];
}
}//先折磨用吧,这是之前一个题的模板
之后我们想啊,c[i]换成什么呢,首先j是背包的容纳量n,可以就是j-i;一步一步的去算,然后w[i]就是存的约数,根据w[i]存的数,他的和是一定是小于n,符合以上的题意。
代码实现:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
int a[N];
int f[N];
int n;
int ys(int n){
int ans=0;
for(int i=2;i<n;i++){
if(n%i==0)ans+=i;
}
return ans;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
for(int i=1;i<=2000;i++){
a[i]=ys(i);
}
cin>>n;
for(int i=1;i<=n;i++){//体积
for(int j=n;j>=0;j--){//每次的计算枚举
if(j>=i)f[j]=max(f[j],f[j-i]+a[i]);
}
}
cout<<f[n]<<endl;
}
这就是01背包的变形运用。
新人博主多多关注点赞。