首页 > 其他分享 >P1734 最大约数和

P1734 最大约数和

时间:2023-03-14 23:56:06浏览次数:51  
标签:约数 背包 最大 int 01 ans P1734 dp

P1734 最大约数和

最大约数和

题目描述

选取和不超过 S 的若干个不同的正整数,使得所有数的约数(不含它本身)之和最大。

输入格式

输入一个正整数 S。

输出格式

输出最大的约数之和。

样例 #1

样例输入 #1

11

样例输出 #1

9

提示

【样例说明】

取数字 4 和 6,可以得到最大值 (1+2)+(1+2+3)=9。

【数据规模】

对于 100 % 的数据,1 ≤ S ≤ 1000。

分析

典型的01背包
Q:01背包是什么?

A:背包问题中最简单的问题。有n件物品和一个容量为V的背包。第i件物品的体积是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。

Q:01背包有什么特别之处?

A:给定几种物品,每种物品有且只有一个,并且有价值和体积两个属性。

Q:在求解01背包的过程中每个物品要考虑几种情况?

A:对于每个物品只需要考虑放与不放两种情况。

1.不放,则不需要处理。

2.放,由于不清楚之前放入的物品占据了多大的空间,需要枚举将这个物品放入背包后可能占据背包空间的所有情况。

由此可以得出,状态转移方程是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

解释一下这个方程,f[i-1][v]指的是不放这件物品,而f[i-1][v-c[i]]+w[i]指的是将第i件放入背包之后的总价值。

for (int i=2;i<=n;i++) {//1的约数和为0,直接从2开始
    for (int j=i;j<=n;j++) {
        f[j]=max(f[j],f[j-i]+a[i]);
    }
}
for(int i=1;i<=n;i++)
    for(int j=n;j>=i;j--)//01背包基本模板 
        dp[j]=max(dp[j],dp[j-i]+a[i]);//i本身当做价钱,a[i]当做价值; 

回到题目本身,约数和用一个简单的函数就可以求出来了。

int yueshuhe(int m){
    int ans=0;
    for (int i=1;i<m;i++){
        if (m%i==0)  ans+=i;
    }
    return ans;
}
int find(int x)
{
    int ans=0;//ans记录x的约数和(注意,不包括自己),还有,一定要将ans初始化为0,本蒟蒻因为没有初始化浪费了半个小时; 
    for(int i=1;i<x;i++)//不包括x本身 
        if(x%i==0)
            ans+=i;
    return ans;
}//简单函数

注意,这里的ans一定要在函数里面初始化为0,如果定义成全局变量会叠加。嗯,会挂。不信你试试吧,我不拦你。
Q:状态转移方程是啥?能吃吗?(问着问着就饿了)

A:能吃。

END

提交答案

#include<cstdio>
#include<algorithm>
using namespace std;
int n;
int a[1001],dp[1001],b[1001];
int find(int x)
{
    int ans=0;//ans记录x的约数和(注意,不包括自己),还有,一定要将ans初始化为0,本蒟蒻因为没有初始化浪费了半个小时; 
    for(int i=1;i<x;i++)//不包括x本身 
        if(x%i==0)
            ans+=i;
    return ans;
}//简单函数
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    a[i]=find(i);//进行一步预处理,a[i]表示i的约数和(不包括自己,第3遍强调) 
    for(int i=1;i<=n;i++)
        for(int j=n;j>=i;j--)//01背包基本模板 
            dp[j]=max(dp[j],dp[j-i]+a[i]);//i本身当做价钱,a[i]当做价值; 
    printf("%d ",dp[n]);//输出就好了 
}

标签:约数,背包,最大,int,01,ans,P1734,dp
From: https://www.cnblogs.com/bujidao1128/p/17216956.html

相关文章