第一行输入三个数字n(0≤n≤999)、m(1≤m≤1000)和k(1≤k≤100000)
接下来m行,每行输入两个数字xi(1≤xi≤100000)和yi(2≤yi≤1000), 表示套餐的价格和套餐内包含的门票数量。
输出牛牛至少要花费的钱的数量。
2 2 5 6 2 13 3
11
#include <bits/stdc++.h> using namespace std; int main() { int n, m, k, weight[1005], price[1005]; cin >> n >> m >> k; price[0] = k; weight[0] = 1; // 单人票,价格为k,作为物品0 for (int i = 1; i <= m; ++i) { // 添加m种套餐(物品) cin >> price[i] >> weight[i]; } int dp[n + 2]; memset(dp, 0x3f, sizeof(dp)); dp[0] = 0; // dp[i]: 购买i张票的最小花费 for (int i = 0; i <= m; ++i) { for (int j = 1; j <= n + 1; ++j) { if (j >= weight[i]) dp[j] = min(dp[j], dp[j - weight[i]] + price[i]); else dp[j] = min(dp[j], price[i]); // 重点 } } cout << dp[n + 1] << endl; return 0; }
/*世界杯门票 这个题可以看做是一个背包问题,人的个数相当于背包的容量,票的价格相当于价值,dp[i]表示买到i张票时的最小花费为dp[i],最后dp[n]即为买到n张票时的最小花费 */ var line1 = readline().split(' '); var n = parseInt(line1[0]), m = parseInt(line1[1]), k = parseInt(line1[2]); n++; var dp = []; for(var i=0;i<=n;i++){ dp[i] = i*k; } for(var i=0;i<m;i++){ var line2 = readline().split(' '); for(var j=1;j<=n;j++){ if(j-line2[1]>=0){ dp[j] = Math.min(dp[j],dp[j-line2[1]]+parseInt(line2[0])); }else{ dp[j] = Math.min(dp[j],parseInt(line2[0])); } } } print(dp[n]);
//基本思路:刚开始不整理,就是将买几张票的钱数先存在dp中,等套餐,单买的情况都存好后, //整理dp[],整理的话有两种情况:①当前的票数要花的最少的钱数等于小于当前票数的最小钱的情况 //之和(因为小于当前票数的最少的钱已经整理好),②等于大于当前票数花的钱和当前的最小数 import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc=new Scanner(System.in); int n=sc.nextInt(); int ticket[]=new int[1001];//表示买i张票所需要的最少的钱 int m=sc.nextInt(); int k=sc.nextInt(); for(int i=0;i<1001;i++){ ticket[i]=i*k; } for(int i=0;i<m;i++){ int mm=sc.nextInt(); int t=sc.nextInt(); ticket[t]=Math.min(ticket[t],mm); } for(int i=1;i<=n+1;i++){ int min=ticket[i]; for(int j=1;j<=1000;j++){ if(j<i) min=Math.min(min,ticket[j]+ticket[i-j]); else min=Math.min(min,ticket[j]); } ticket[i]=min; } System.out.println(ticket[n+1]); } }
写出暴力递归,再改写成动动态规划,未进行任何优化。
/**
*
* 思路:
* 遍历每种套餐组合,每种套餐均可购买 0 ~ 当前缺少门票/当前套餐提供的票数 (向上取整),最后所得门票大于需求 或者 到达数组尾部 时返回。。
*
* ps:
* 单买门票等价于票数为1的套餐。
*
* @author Yanjie
*
*/
public class BuyTicket {
public static void main(String[] args) throws Exception {
Scanner in = new Scanner(new FileInputStream("F:\\java\\JavaLearning\\src\\nowcoder\\praticetest\\BuyTicakets.txt"));
int n = in.nextInt();
int m = in.nextInt();
int k = in.nextInt();
// 套餐数组,dp[][0]:价格,dp[][1]:票数
int[][] pacakges = new int[m + 1][2];
pacakges[0][0] = k;
pacakges[0][1] = 1;
for (int i = 1; i <= m; i++) {
pacakges[i][0] = in.nextInt();
pacakges[i][1] = in.nextInt();
}
System.out.println(process1(pacakges, n, 0, 0));
System.out.println(process2(pacakges, n));
}
/**
* 暴力递归
*
* @author Yanjie
*
* @param pacakges
* @param n
* @param curIndex
* @param curTickets
* @return
*/
public static int process1(int[][] pacakges, int n, int curIndex, int curTickets) {
// base case
if (curTickets >= n + 1) { // 票数已够
return 0;
}
if (curIndex == pacakges.length) { // 票数未够但已无可用套餐,该方案不满足条件,废弃。
return -1;
}
int minMoney = (n + 1) * pacakges[0][0];
int curMaxNum = (int) Math.ceil( (double) ((n + 1) - curTickets) / pacakges[curIndex][1] ); // 向上取整,即可以多买票。
for (int k = 0; k <= curMaxNum; k++) {
int money = process1(pacakges, n, curIndex + 1, curTickets + k * pacakges[curIndex][1]);
if (money == -1) {
continue;
} else {
money += pacakges[curIndex][0] * k; // money = 当前套餐花费 + 后续套餐花费
}
minMoney = Math.min(minMoney, money);
}
return minMoney;
}
/**
* 动态规划
*
* @author Yanjie
*
* @param pacakges
* @param n
* @return
*/
public static int process2(int[][] pacakges, int n) {
// dp
int[][] dp = new int[pacakges.length + 1][n + 2];
// base case
for (int j = 0; j <= n + 1; j++) {
dp[pacakges.length][j] = -1;
}
// 普通位置
for (int i = pacakges.length - 1; i >= 0; i--) {
for (int j = n; j >= 0; j--) {
int minMoney = (n + 1) * pacakges[0][0];
int curMaxNum = (int) Math.ceil( (double) ((n + 1) - j) / pacakges[i][1] );
for (int k = 0; k <= curMaxNum; k++) {
int money = 0;
if (j + k * pacakges[i][1] <= n + 1) { // 数组越界处理,票数是否够数
money = dp[i + 1][j + k * pacakges[i][1]];
}
if (money == -1) {
continue;
} else {
money += pacakges[i][0] * k;
}
minMoney = Math.min(minMoney, money);
}
dp[i][j] = minMoney;
}
}
return dp[0][0];
}
}
//动态规划,我更喜欢使用二维数组,更容易理解 #include <iostream> #include <vector> #include <limits.h> using namespace std; int min(int a, int b) { return (a < b) ? a :b; } int main() { int n, m, k; int x, y; while(cin >> n >> m >> k) { vector<int> price(m+1); //price[i]表示第i种方案对应的价格 vector<int> count(m+1); //count[i]表示第i中方案对应的人数 price[0] = k; count[0] = 1; for(int i = 1; i <= m; i++) { cin >> x >> y; price[i] = x; count[i] = y; } //定义dp[i][j]:用前i种方案凑j个人的最少费用 //最后输出dp[m][n+1]即可 vector<vector<int> > dp(m+1, vector<int>(n+2, INT_MAX)); //1.对dp[0][j]:用第0种方法去凑j个人,只能是count[0]的倍数 for(int j = 0; j <= n+1; j++) { if(j%count[0] == 0) dp[0][j] = (j/count[0])*price[0]; } //2.对dp[i][0]:用前i种方法去凑0个人,即不需要钱,全部置0 for(int i = 0; i <= m; i++) dp[i][0] = 0; //3.对dp[i][j]: for(int i = 1; i <= m; i++) for(int j = 1; j <= n+1; j++) { if(j-count[i] >= 0) dp[i][j] = min(dp[i-1][j], dp[i][j-count[i]]+price[i]); else dp[i][j] = min(dp[i-1][j], price[i]); } cout << dp[m][n+1] << endl; } return 0; }
人的个数相当于背包的容量,票的价格相当于价值,dp[i]表示买到i张票时的最小花费为dp[i],最后dp[n + 1]即为买到n + 1张票时的最小花费
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNext()) { int n = sc.nextInt(); int m = sc.nextInt(); int k = sc.nextInt(); int[] dp = new int[n + 2]; for(int i = 1; i <= n + 1; i++) { dp[i] = i * k; } int x, y = 0; while(m-- > 0) { x = sc.nextInt(); y = sc.nextInt(); for(int i = 1; i <= n + 1; i++) { if(i - y >= 0) { dp[i] = Math.min(dp[i], dp[i - y] + x); } else { dp[i] = Math.min(dp[i], x); } } } System.out.println(dp[n + 1]); } } }
#include <iostream> #include <algorithm> using namespace std; int y_man[1005]; int x_price[1005]; int d[1005];//费用矩阵 int main() { int n,m,k; cin>> n>> m>>k; x_price[0] = k ;y_man[0] = 1; for(int i =1 ;i<=m ;i++) cin >>x_price[i] >>y_man[i]; d[0] = 0; for(int i = 1;i<=n+1 ;i++) { d[i] = (n+1)*k; //初始化的d[1-(n+1)] } for(int i= 0;i<=m;i++) //取前m中方案 求的费用d[j] ;注意 ,一个人单独购票也是一种方案 { for(int j= 1;j<=n+1 ;j++) //更新 费用d[] 矩阵 { if(j >=y_man[i]) d[j] = min(d[j],d[j-y_man[i]]+x_price[i]); else d[j] = min(d[j],x_price[i]);//非常重要,当人数小于团体票时, //有可能出现团体票费用比其他组合还便宜 } } cout << d[n+1]; return 0; }
#include<iostream>
#include <iostream>
#include <vector>
#include <algorithm>
#include <limits.h>
using namespace std;
int cost;
int k;
bool com(pair<int,int>& a,pair<int,int>&b)
{
return a.first/a.second>b.first/b.second;
}
void core(vector<pair<int,int>>& co,int idx,int n,int num,int cos,int total)
{
if(num>=total)
{
cost=min(cost,cos);
return;
}
if(cos>cost)
return;
cost=min(cos+(total-num)*k,cost);
for(int i=idx;i<n;i++)
core(co,i,n,num+co[i].second,cos+co[i].first,total);
}
int main()
{
int n,m;
while(cin>>n>>m>>k)
{
vector<pair<int,int>> co(m);
for(int i=0;i<m;i++)
cin>>co[i].first>>co[i].second;
sort(co.begin(),co.end(),com);
cost=INT_MAX;
core(co,0,m,0,0,n+1);
cout<<cost<<endl;
}
}
//完全背包 #include<iostream> #include<stdio.h> #include<string.h> #include<queue> #include<algorithm> using namespace std; #define inf 0x3f3f3f3f int v[1010],w[1010]; int dp[2100]; int main() { int m,n; for(int i=0;i<=2099;i++) dp[i]=inf; scanf("%d%d%d",&n,&m,&w[0]); v[0]=1; n++; int maxx=-1; dp[0]=0; for(int i=1;i<=m;i++) { scanf("%d%d",&w[i],&v[i]); if(maxx<v[i]) maxx=v[i]; } for(int i=0;i<=m;i++) { for(int k=0;k*v[i]<=n+maxx;k++) { for(int j=k*v[i];j<=n+maxx;j++) { dp[j]=min(dp[j],dp[j-v[i]]+w[i]); } } } int minn=inf; for(int i=n;i<=n+maxx;i++) { minn=min(dp[i],minn); } printf("%d\n",minn); }
public class Main { // 动态规划:dp[i]表示i个人的最小花销 public static void main(String[] args) { java.util.Scanner sc = new java.util.Scanner(System.in); int n = sc.nextInt(), m = sc.nextInt(), k = sc.nextInt(), i, j; int price, num, dp[] = new int[n+2];// dp[0] == 0 for (i = 1; i < n+2; ++i) dp[i] = k * i; for (i = 0; i < m; ++i) { price = sc.nextInt(); num = sc.nextInt(); for (j = 1; j < n+2; ++j) dp[j] = Math.min(dp[j], dp[Math.max(0, j-num)] + price); } System.out.println(dp[n+1]); } }
改了很久没过:不知道为什么? 我自己编的几个测试数据都没问题
那个472是怎么算出来的?
我手动检验了一下,实在凑不出来472,反倒是凑出来了644,就是 22 + 103 + 173*3 ,这三种套餐刚好凑够117张票,结果是644元钱。。。
还有一点就是,我的理解是,不能多买,用套餐凑的话,必须得凑够n+1张
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int k = in.nextInt();
int[][] data = new int[m+1][2];
for(int i=0;i<m&&in.hasNextInt();i++){
data[i][0] = in.nextInt();
data[i][1] = in.nextInt();
}
//单张买也算作一种套餐: 花费k,人数1
data[m][0] = k;
data[m][1] = 1;
if(n==0){
System.out.println(k);
return;
}
long[] dp = new long[n+2]; //当总人数为i时,最少花费
for(int i=0;i=data[j][1]){//
dp[i] = Math.min(dp[i], dp[i-data[j][1]]+data[j][0]);
}
}
}
System.out.println(dp[n+1]);
in.close();
}
}
116 26 450
230 15
531 70
777 63
589 61
266 81
322 77
517 73
820 68
241 77
103 42
256 91
750 87
866 51
569 97
524 83
173 2
22 69
653 14
846 17
896 69
111 90
194 68
326 2
335 18
175 79
933 55
472
你的输出为: