问题A: 动态规划-01背包问题
题目描述
给定n(1<=n<=10)种物品和一背包,物品i (1≤i≤n) 的重量是wi (wi > 0),其价值为vi (vi > 0),背包的容量为c (0<c<=20),问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
输入
第一行输入两个整数,分别表示n个物品和背包容量c
第二行输入n个整数,分别表示每个物品的重量
第三输入n个整数,分别表示每个物品的价值
输出
第一行输出最大价值
样例输入
复制
3 10 4 3 5 50 40 60
样例输出
复制
110
提示
#include<stdio.h> int m[11][21],w[11],v[11]; //第0行不存放有效数据 int knapbag(int n, int c) { for(int j=0; j<=c; j++){//填写第n行数据 } for(int i=n-1; i>=1; i--) { //分别填写第n-1,n-2,...1行数据 } return m[1][c];//返回最大值 } int main(void) { int n,c,result; //1<=n<=10; 0<c<=20 scanf("%d %d",&n,&c); for (int i=1; i<=n; i++) scanf("%d",&w[i]); for (int j=1; j<=n; j++) scanf("%d",&v[j]); result=knapbag(n,c); printf("%d\n",result); return 0; }
#include <stdio.h>
int m[11][21], w[11], v[11]; // 第0行不存放有效数据
int knapbag(int n, int c) {
for (int j = 0; j <= c; j++) {
m[0][j] = 0; // 填写第0行数据
}
for (int i = 1; i <= n; i++) {
m[i][0] = 0; // 填写第i列数据
for (int j = 1; j <= c; j++) {
if (w[i] <= j) { // 可以放入背包
int temp1 = m[i - 1][j - w[i]] + v[i]; // 将第i个物品放入背包
int temp2 = m[i - 1][j]; // 不放入背包
m[i][j] = (temp1 > temp2) ? temp1 : temp2; // 取较大值
} else { // 不能放入背包
m[i][j] = m[i - 1][j];
}
}
}
return m[n][c]; // 返回最大值
}
int main(void) {
int n, c, result; // 1<=n<=10; 0<c<=20
scanf("%d %d", &n, &c);
for (int i = 1; i <= n; i++)
scanf("%d", &w[i]);
for (int j = 1; j <= n; j++)
scanf("%d", &v[j]);
result = knapbag(n, c);
printf("%d\n", result);
return 0;
}
问题B: 动态规划-硬币问题
题目描述
已知有n(1<=n<=10)种不同面值的硬币,各种硬币面值存于数组T[1:n],各种面值的个数存在数组NUM[1:n]中,需要找零的钱数为m(0<=m<=100)。设计一个算法,计算找钱m的最少硬币数以及不同硬币面值的个数(使用动态规划)。
要求:
第1行输入1个整数,表示不同面值的硬币数n。
第2行输入2个整数,分别表示第2个硬币的面值和个数。
第3行输入2个整数,分别表示第3个硬币的面值和个数。
...
第n+1行输入2整数,分别表示第n个硬币的面值和个数。
第n+2行输入1整数,表示钱数m。
第n+3行输出1整数,表示计算出来的最少硬币数量。
最后1行直接输出每种硬币的个数(相邻两个数据之间用1个空格隔开)。
输入
3
1 3
5 4
11 3
20
输出
4
0 4 0
样例输入
复制
4 1 3 2 4 5 2 10 2 17
样例输出
复制
3 0 1 1 1
提示
#include <stdio.h> #define MAXINT 1000000 //假设MAXINT表示内存中能够存储的最大整数 int T[11], NUM[11], X[11]; //T[i]:第i种硬币面值,NUM[i]:第i种硬币个数,X[i]表示取得最优值时第i种硬币的个数 int c[11][101]; // 需要填写的二维表格 int coin(int n,int m) { for(int j=0; j<=m; j++) { //填写表格中第n行数据 if (j%T[n]==0 && j/T[n]<=NUM[n]) c[n][j]=j/T[n]; else c[n][j]=MAXINT; } for(int i=n-1; i>=1; i--){ for(int j=0; j<=m; j++){ } } return c[1][m]; } void printOptimalSolution(int n, int j) { for(int i=1; i<=n; i++) { if (c[i][j]==c[i+1][j]) X[i]=0; else { } } } int main(void) { int i,n,m,result; scanf("%d", &n); for(i=1; i<=n; i++) { scanf("%d", &T[i]); scanf("%d", &NUM[i]); } scanf("%d",&m); result=coin(n,m); printf("%d\n", result); printOptimalSolution(n,m); for(i=1; i<=n; i++) printf("%d ",X[i]); return 0; }
#include <stdio.h>
#define MAXINT 1000000 //假设MAXINT表示内存中能够存储的最大整数
int T[11], NUM[11], X[11]; //T[i]:第i种硬币面值,NUM[i]:第i种硬币个数,X[i]表示取得最优值时第i种硬币的个数
int c[11][101]; // 需要填写的二维表格
int coin(int n,int m) {
for(int j=0; j<=m; j++) { //填写表格中第n行数据
if (j%T[n]==0 && j/T[n]<=NUM[n]) c[n][j]=j/T[n];
else c[n][j]=MAXINT;
}
for(int i=n-1; i>=1; i--){//i<n
for(int j=0; j<=m; j++){
c[i][j]=c[i+1][j];
for(int k=1;k<=(j/T[i]<NUM[i]?j/T[i]:NUM[i]);k++){
if(c[i][j]>k+c[i+1][j-k*T[i]]){
c[i][j]=k+c[i+1][j-k*T[i]];
}
}
}
}
return c[1][m];
}
void printOptimalSolution(int n, int j) {
for(int i=1; i<=n; i++) {
if (c[i][j]==c[i+1][j]) X[i]=0;
else {
for(int k=1;k<=(j/T[i]<NUM[i]?j/T[i]:NUM[i]);k++){
if(c[i][j]==k+c[i+1][j-k*T[i]]){
X[i]=k;
j=j-k*T[i];
break;
}
}
}
}
}
int main(void) {
int i,n,m,result;
scanf("%d", &n);
for(i=1; i<=n; i++) {
scanf("%d", &T[i]);
scanf("%d", &NUM[i]);
}
scanf("%d",&m);
result=coin(n,m);
printf("%d\n", result);
printOptimalSolution(n,m);
for(i=1; i<=n; i++) printf("%d ",X[i]);
return 0;
}
问题C: 动态规划-最长公共子序列
题目描述
给定两个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn}(0<=m,n<=80),要求找出X和Y的最长公共子序列(“BCBA”是“ABCBDAB”的子序列)。 最长公共子序列是一个十分实用的问题,它可以描述两段文字之间的“相似度”,即它们的雷同程度,从而能够用来辨别抄袭。对一段文字进行修改之后,计算改动前后文字的最长公共子序列,将除此子序列外的部分提取出来,这种方法判断修改的部分,往往十分准确。
输入
第一行输入第一个子序列
第二行输入第二个子序列
输出
第一行输出最长公共子序列的长度
第二行输出最长公共子序列
样例输入
复制
ABCBDAB BDCABA
样例输出
复制
4 BCBA
提示
#include <stdio.h> #include <string.h> #define MAXLEN 81 int b[MAXLEN][MAXLEN],c[MAXLEN][MAXLEN]; // c是计算最优值时需要填写的二维表格,b是计算最优解时需要填写的二维表格 void LCSLength(char x[], char y[], int m , int n) { int i,j,k; for(i=0; i<=n; i++) c[0][i]=0; //填写第0行数据 for(i=0; i<=m; i++) c[i][0]=0; //填写第0列数据 for(i=1; i<=m; i++) { //分别填写第i行第j列对应的单元格数据 for(j=1; j<= n; j++) { if(x[i]==y[j]) { } else if(c[i-1][j]>=c[i][j-1]) { } else { } } } } void LCS(char x[], int i, int j) { if(i==0 || j==0) return; if(b[i][j]==1) { } else if(b[i][j]==2) { } else { } } int main(void) { char x[MAXLEN+1],y[MAXLEN+1]; //下标为0的单元不存放有效数据 int m,n; scanf("%s",x); m=strlen(x); scanf("%s",y); n=strlen(y); strcpy(x+1,x); strcpy(y+1,y); //字符串x和y中的字符分别向后移一位,目的是让0号单元不存放有效数据 LCSLength(x,y,m,n); printf("%d\n",c[m][n]); LCS(x,m,n); return 0; }
#include <stdio.h>
#include <string.h>
#define MAXLEN 81
int b[MAXLEN][MAXLEN],c[MAXLEN][MAXLEN]; // c是计算最优值时需要填写的二维表格,b是计算最优解时需要填写的二维表格
void LCSLength(char x[], char y[], int m , int n) {
int i,j,k;
for(i=0; i<=n; i++) c[0][i]=0; //填写第0行数据
for(i=0; i<=m; i++) c[i][0]=0; //填写第0列数据
for(i=1; i<=m; i++) { //分别填写第i行第j列对应的单元格数据
for(j=1; j<= n; j++) {
if(x[i]==y[j]) {
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
} else if(c[i-1][j]>=c[i][j-1]) {
c[i][j]=c[i-1][j];
b[i][j]=2;
} else {
c[i][j]=c[i][j-1];
b[i][j]=3;
}
}
}
}
void LCS(char x[], int i, int j) {
if(i==0 || j==0) return;
if(b[i][j]==1) {
LCS(x,i-1,j-1);
putchar(x[i]);
} else if(b[i][j]==2) {
LCS(x,i-1,j);
} else {
LCS(x,i,j-1);
}
}
int main(void) {
char x[MAXLEN+1],y[MAXLEN+1]; //下标为0的单元不存放有效数据
int m,n;
scanf("%s",x);
m=strlen(x);
scanf("%s",y);
n=strlen(y);
strcpy(x+1,x);
strcpy(y+1,y); //字符串x和y中的字符分别向后移一位,目的是让0号单元不存放有效数据
LCSLength(x,y,m,n);
printf("%d\n",c[m][n]);
LCS(x,m,n);
return 0;
}
问题D: 动态规划-最长单调递增子序列
题目描述
用动态规划设计一个算法,要求找出由n个整数组成的序列的最长单调递增子序列的个数(假设所有的元素都不相同)。
输入
第一行输入一个整数,表示有n个整数。
第二行输入n个整数。
输出
第三行输出最长单调递增子序列的个数。
样例输入
复制
6 1 3 2 5 4 0
样例输出
复制
3
#include <stdio.h>
int main() {
int n;
scanf("%d", &n);
int nums[n];
for (int i = 0; i < n; i++) {
scanf("%d", &nums[i]);
}
int dp[n];
int max_len = 1;
for (int i = 0; i < n; i++) {
dp[i] = 1;
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = dp[j] + 1 > dp[i] ? dp[j] + 1 : dp[i];
}
}
max_len = dp[i] > max_len ? dp[i] : max_len;
}
printf("%d", max_len);
return 0;
}