算法设计与分析-软件-动态规划

问题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;
}

  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值