有重量分别为 3,5,7 公斤的三种货物,和一个载重量为 X 公斤的箱子(不考虑体积等其它因素,只计算重量)
需要向箱子内装满X公斤的货物,要求使用的货物个数尽可能少(三种货物数量无限)
数据范围: 
输入箱子载重量(一个整数)。
如果无法装满,输出 -1。
如果可以装满,输出使用货物的总个数。
4
-1
无法装满
8
2
使用1个5公斤,1个3公斤货物
#include <bits/stdc++.h>
using namespace std;
int main(){
int x;
cin>>x;
vector<int> dp(x+1, INT_MAX);
dp[3] = dp[5] = dp[7] = 1;
dp[6] = 2;
for(int i=8;i<=x;i++){
if(dp[i-3]==INT_MAX && dp[i-5]==INT_MAX && dp[i-7]==INT_MAX)
dp[i] = INT_MAX;
else
dp[i] = min(min(dp[i-3],dp[i-5]), dp[i-7]) + 1;
}
cout<<((dp[x]!=INT_MAX)?dp[x]:-1)<<endl;
return 0;
} //动态规划背包问题
#include <bits/stdc++.h>
using namespace std;
int main(){
int n,num[3]={3,5,7};
cin>>n;
vector<int> dp(n+1,9999);
for(int j=0;j<=n;j++)
if(j%num[0]==0)
dp[j]=j/num[0];
for(int i=1;i<3;i++)
for(int j=0;j<=n;j++)
if(j>=num[i])
dp[j]=min(dp[j-num[i]]+1,dp[j]);
if(dp[n]==9999)
cout<<-1;
else
cout<<dp[n];
return 0;
}
#include<iostream>
#include<vector>
#define MAX 10000
using namespace std;
int min(int a,int b){
return a<b?a:b;
}
int main(){
int X;
cin>>X;
vector<int> dp(X+1,MAX);
dp[3]=1;
dp[5]=1;
dp[6]=2;
dp[7]=1;
for(int sum=8;sum<=X;sum++){
dp[sum]=min(dp[sum-3],min(dp[sum-5],dp[sum-7]))+1;
}
cout<<(dp[X]>=MAX?-1:dp[X])<<endl;
return 0;
} import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int X = Integer.parseInt(br.readLine().trim());
int[] dp = new int[10001]; // X的范围是[1,10000]
Arrays.fill(dp, 10001);
// 0,1,2,4无法装满
dp[3] = dp[5] = dp[7] = 1; // 这三种情况只需要一个货物
dp[6] = 2; // X=6时需要两个重为3的货物
for(int weight = 8; weight <= X; weight++){
// weight这个重量减去3,5,7都凑不出来,因此weight也凑不出来
if(dp[weight - 3] == 10001 && dp[weight - 5] == 10001 && dp[weight - 7] == 10001)
dp[weight] = 10001;
else
dp[weight] = Math.min(dp[weight - 3], Math.min(dp[weight - 5], dp[weight - 7])) + 1;
}
System.out.println(dp[X] != 10001? dp[X]: -1);
}
} import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for (int i = n/7; i >= 0; i--) {
for (int j = n/5; j >= 0; j--) {
if (i*7 + j*5 > n) {
continue;
} else if (i*7 + j*5 == n) {
System.out.println(i+j);
return;
} else if ((n - i*7 - j*5) % 3 == 0) {
int k = (n - i*7 - j*5) / 3;
System.out.println(i+j+k);
return;
}
}
}
System.out.println(-1);
}
} import java.util.*;
// X<=14的时候每一种值是特殊的,将结果枚举出来
// X>14的时候可以将它拆为两个部分(7+X%7)+7*(X/7-1)
// 前一部分是<=14的部分,后一部分是7的整数倍
// 例如对于18,可以拆为11+7,11需要3个货物,7需要一个,答案就是4
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int [] r14 = {-1, -1, -1, 1, -1, 1, 2, 1, 2, 3, 2, 3, 2, 3, 2};
int X = scanner.nextInt();
if (X <= 14) {
System.out.println(r14[X]);
} else {
int temp = X / 7 - 1;
System.out.println(temp + r14[X % 7 + 7]);
}
}
}
public class Main {
/**
* 哎,一直在分析哪些可以装满哪些不能装满的情况,结果发现只有1,2,4不能装满...rlg
* 参考了 "皮皮虾没有虾的"同学的分析才明白:
* 对7取余,余数为1,2,3可以装满,1可以视为1+7=3+5,count+1;
* 余数为2,4,6可对应9,11,13的情况...... count +=2;
*/
public static void main(String[] args) throws IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
int x = Integer.parseInt(bf.readLine());
if (x == 1 || x == 2 || x == 4) {
System.out.println(-1);
} else {
int count = 0;
count += x / 7;
x = x % 7;
if (x == 0) {
System.out.println(count);
} else {
System.out.println(x % 2 == 0 ? count + 2 : count + 1);
}
}
}
}
#include<iostream>
#include<vector>
using namespace std;
void dfs(vector<int>& temp,int target,int val);//回溯法
vector<vector<int>> res;//保存组合方法
bool flag=true;//是否已找到方法
int main()
{
int target;
cin>>target;
vector<int> temp;//方法暂存变量
dfs(temp,target,7);//先7
dfs(temp,target,5);//后5
dfs(temp,target,3);//后3
if(res.empty())
cout<<"-1"<<endl;//没有方法
else
cout<<res[0].size()<<endl;//输出货物最少的方法
return 0;
}
void dfs(vector<int>& temp,int target,int val)
{
temp.push_back(val);//当前选取的货物放入方法暂存
if(target==val)//箱子装满
{
res.push_back(temp);//当前方法放入结果
flag=false;//已找到方法
}
//不是3选1 而是优先级 7>5>3 否则正确组合可能被跳过
if(target-val>=7&&flag)//当前剩余值大于等于7
dfs(temp,target-val,7);//先放7
if(target-val>=5&&flag)//当前剩余值大于等于5
dfs(temp,target-val,5);//再放置5
if(target-val>=3&&flag)//当前剩余值大于等于3
dfs(temp,target-val,3);//再放置3
temp.pop_back();//尾回溯 删除本轮添加的货物
} DP解法。dp[i]代表装满重量为i的箱子所需的最少货物数目,那么dp[i]=min(dp[i-3],dp[i-5],dp[i-7])+1。初始化并模拟递推过程即可。使用INT_MAX代表不能被装满。 #include<iostream>
#include<vector>
#include<limits.h>// for INT_MAX
using namespace std;
int main()
{
int target;
cin>>target;
vector<int> dp(target+1,INT_MAX);//dp[i] 装满体积为i的箱子所需最少货物数目
dp[3]=1;
dp[5]=1;
dp[7]=1;
dp[6]=2;//初始化
for(int i=8;i<=target;i++)//递推过程
{
int a=dp[i-3],b=dp[i-5],c=dp[i-7];//a b c分别代表i-3 i-5 i-7再装一个货物
if(a==INT_MAX&&b==INT_MAX&&c==INT_MAX)
dp[i]=INT_MAX;//表示i不能被被装满
else
dp[i]=min(min(a,b),c)+1;//最少的货物数目+1
}
if(dp[target]==INT_MAX)
cout<<"-1"<<endl;//不能被被装满
else
cout<<dp[target]<<endl;//输出最少货物数目
return 0;
} X = int(input())
dp = [float('inf')]*8
dp[3],dp[5],dp[6],dp[7]=1,1,2,1
if (X<8):
res = dp[X]
else:
for i in range(8, X+1):
temp = min(dp[i-3], dp[i-5], dp[i-7])
if temp==float('inf'):
dp.append(float('inf'))
else:
dp.append(temp+1)
res = dp[X]
print(res) if res !=float('inf') else print(-1)
/*
回溯法。
从7开始试,找到第一个正好能装满的,便是答案。
*/
import java.util.*;
public class Main {
static int ans = Integer.MAX_VALUE;
static boolean flag = false;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
leastGoods357(0, n);
if (ans == Integer.MAX_VALUE) {
System.out.println(-1);
} else {
System.out.println(ans);
}
}
static void leastGoods357(int cnt, int n) {
if (flag) return;
if (n == 0) {
ans = Math.min(ans, cnt);
flag = true;
return;
} else if (n < 0) {
return;
} else {
leastGoods357(cnt + 1, n - 7);
leastGoods35(cnt + 1, n - 5);
leastGoods3(cnt + 1, n - 3);
}
}
static void leastGoods35(int cnt, int n) {
if (flag) return;
if (n == 0) {
ans = Math.min(ans, cnt);
flag = true;
return;
} else if (n < 0) {
return;
} else {
leastGoods35(cnt + 1, n - 5);
leastGoods3(cnt + 1, n - 3);
}
}
static void leastGoods3(int cnt, int n) {
if (flag) return;
if (n == 0) {
ans = Math.min(ans, cnt);
flag = true;
return;
} else if (n < 0) {
return;
} else {
leastGoods3(cnt + 1, n - 3);
}
}
}
import java.util.Scanner;
public class Main {
static int temp = 0;
public static void dfs(int count, int rest) {
if (rest < 0) {//如果-3,-5或者-7小于0了,说明凑不齐,赶紧溜了
return;
}
if (rest == 0) {
System.out.println(temp*15+count);
System.exit(0);
}
dfs(count + 1, rest - 7);
dfs(count + 1, rest - 5);
dfs(count + 1, rest - 3);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
temp = n / 105;
dfs(0, n % 105);
System.out.println(-1);
}
} import java.util.*;
// 换零钱
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int[] coins = {3, 5, 7};
int x = in.nextInt();
int[] dp = new int[x + 1];
Arrays.fill(dp, x + 1);
dp[0] = 0;
for (int coin : coins) {
for (int i = coin; i <= x; i++) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}
System.out.print(dp[x] > x ? -1 : dp[x]);
}
} private static int calc(int a) {
int h1 = 3;
int h2 = 5;
int h3 = 7;
int max7 = a / h3;
int max5 = 0;
int max3 = 0;
int i7 = max7;
int i5 = 0;
int i3 = 0;
for (; i7 >= 0; i7--) {
max5 = (a - i7 * h3) / h2;
int a2 = (a - i7 * h3);
i5 = max5;
for (; i5 >= 0; i5--) {
if ((a2 - i5 * h2) % h1 == 0) {
max3 = (a2 - i5 * h2) / h1;
return (i7 + i5 + max3);
}
}
}
return -1;
} /**
* 升级版来一个,货物的重量也可输入
* 参数a:总重量
* h1: 最轻的货物
* h2:次轻的货物
* h3:最重的货物
*/
private static int calc(int a, int h1, int h2, int h3) {
// 最重的货物直接装满
if(a % h3 == 0){
return a / h3;
}
// 尝试用最重的两种货物装满
int result1 = -1;
int n1 = a / h3;
while(n1 >= 0){
int unUse1 = a - n1 * h3;
if(unUse1 % h2 == 0){
// 满足条件,退出循环
result1 = n1 + unUse1 / h2;
break;
}
// 去掉一个最重的货物再尝试
n1--;
}
// 最后尝试三种货物组合
int result2 = -1;
n1 = a / h3;
// 是否结束循环
boolean flag = false;
while(n1 >= 0){
int unUse1 = a - n1 * h3;
int n2 = unUse1 / h2;
while(n2 >= 0){
int unUse2 = unUse1 - n2 * h2;
if(unUse2 % h1 == 0){
result2 = n1 + n2 + unUse2 / h1;
flag = true;
break;
}
n2--;
}
if(flag){
break;
}
// 去掉一个最重的货物再尝试
n1--;
}
if(result1 == -1){
// 当最重的两种货物组合无法装满时,返回三种货物组合结果
return result2;
}
if(result2 == -1){
// 当三种货物组合无法装满时,返回最重的两种货物组合结果
return result1;
}
if(result1 == -1 && result2 == -1){
// 所有组合都无法装满
return -1;
}
// 当最终的两种货物组合和三种货物组合都能装满时,返回数量最少的那个组合结果
return result1 > result2 ? result2 : result1;
} #include<bits/stdc++.h>
using namespace std;
int main()
{
int x;
cin >> x;
for(int i = 0; i <= x / 3; ++i)
for(int j = 0; j <= (x - 3 * i) / 5; ++j)
for(int k = 0; k <= (x - 3 * i - 5 * j) / 7; ++k)
{
if(x == 3*i + 5*j + 7*k)
{
cout << i + j + k;
return 0;
}
}
cout << -1;
return 0;
}
//因为要求最少数量,所以尽量多放重的货物,所以第一层循环代表重量为3,第二层循环代表重量为5的货物,第三层代表
//重量为7,直接三层循环暴力破解
const int maxn = 10000+5;
#include<iostream>
#include<vector>
#include<cstring>
int dp[maxn];
using namespace std;
int main(){
int X;
cin >> X;
//dp[0] = 0;
memset(dp,0x3f3f3f,sizeof dp);
dp[0] = 0;
vector<int> goods = {3,5,7};
for(int i = 1;i <= X;i++){
for(int j = 0;j < 3;j++){
if(i - goods[j] >= 0){
if(dp[i-goods[j]]!=1061109567)
dp[i] = min(dp[i],dp[i-goods[j]] + 1);
}
}
}
//for(int x : dp) cout << x << " ";
//cout << endl;
if(dp[X] == 1061109567) cout << -1 << endl;
else cout << dp[X] << endl;
return 0;
}
经典背包问题
递归 #coding=utf-8 def k5(n):#对于5与3的分配 d,f,r=n%5,1,n//5#对n取余 while d%3!=0:#如果余数是3的倍数就可以组合 d+=5#如果不是就加5 r-=1 if d>n:#直到超过n那就说明不能组合 f=0 return -1 break if f: return d//3+r#d//3是3个数,r是5的个数 def k7(n):#对于7与(5&3)的分配 d,f,re=n%7,1,n//7#对n取余 while k5(d)==-1:#如果余数是可以用3与5组合,那么就成立 d+=7#不能组合就加7 re-=1 if d>n:#超过时候不能成立 f=0 return -1 break if f: return k5(d)+re#k5(d)是5与3组合后总数,re是7的个数 while 1: try: x=int(input()) print(k7(x)) except: break