算法(七)动态规划----资源问题

一、机器分配问题

1.问题引入:

总公司拥有高效生产设备N台,准备分给下属的M个公司。各分公司若获得这些设备,可以为国家提供一定的盈利。问:如何分配这M台设备才能使国家得到的盈利最大?求出最大盈利值。其中N《=15,M〈=10。分配原则:每个公司有权获得任意数目的设备,但总台数不得超过总设备数N。

 

第一行输入两个数,第一个数是分公司数M,第二个数是设备台数N。接下来是一个M*N的矩阵,表明了第I个公司分配J台机器的盈利。

最后输出最大盈利

样例输入:
3 3 30 40 50 20 30 50 20 25 30

样例输出:

70

2.思路分析:

动态规划是由递归演变而来的,就是记录递归的中间过程,所以动态规划牺牲空间来优化了时间,其实方法还是递归搜索。让公司个数为状态,一个是阶段另一个肯定是状态了。我们可以把状态设置为个数这样我们就能考虑到因为个数不同而价值不同计算了 , 我们把公司设置为阶段。我们设置数组为d[i][j]表示前i个公司用j个机器。我们用 d[i][j]来记录到i阶段的j台机器时价值的最大值。

如何得到d[i][j]呢 , 我们可以从d[i-1]行中找,如果遍历到第i-1个公司已经用了K台机器,则第i个公司可以用j-k(k<=j)台机器。由此得到状态转移方程为d[i][j]=Max{d[i-1][k]+value[i][j-k]}。

3.代码如下:

 

package  动态规划资源问题  ;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class 机器分配问题{
	public static void main(String args[]) throws IOException{
		BufferedReader buf=new BufferedReader(new InputStreamReader(System.in));
		String s=buf.readLine();
		String s1[]=s.split(" ");
		int m=Integer.parseInt(s1[0]);//公司
		int n=Integer.parseInt(s1[1]);
		int v[][]=new int[m+1][n+1]; //有效下标从1开始
		for(int i=1;i<=m;i++){
			String t=buf.readLine();
			String t1[]=t.split(" ");
			for(int j=1;j<=n;j++)
				v[i][j]=Integer.parseInt(t1[j-1]);
		}
		int max=fun(v,m,n);
		System.out.print(max);
	}
	public static int fun(int v[][],int m,int n){
		int dp[][]=new int[m+1][n+1];//有效下标从1开始
		for(int i=0;i<=m;i++) dp[i][0]=0;
		for(int i=0;i<=n;i++) dp[0][i]=0;
		for(int i=1;i<=m;i++){
			for(int j=1;j<=n;j++){
				for(int k=0;k<=j;k++)
				dp[i][j]=Math.max(dp[i][j], 
						dp[i-1][k]+v[i][j-k]);//前i个公司用了k台机器,则第i个公司可以用j-k台机器
			}
		}
		return dp[m][n];
	}
	

}ackage  动态规划资源问题  ;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class 机器分配问题{
	public static void main(String args[]) throws IOException{
		BufferedReader buf=new BufferedReader(new InputStreamReader(System.in));
		String s=buf.readLine();
		String s1[]=s.split(" ");
		int m=Integer.parseInt(s1[0]);//公司
		int n=Integer.parseInt(s1[1]);
		int v[][]=new int[m+1][n+1]; //有效下标从1开始
		for(int i=1;i<=m;i++){
			String t=buf.readLine();
			String t1[]=t.split(" ");
			for(int j=1;j<=n;j++)
				v[i][j]=Integer.parseInt(t1[j-1]);
		}
		int max=fun(v,m,n);
		System.out.print(max);
	}
	public static int fun(int v[][],int m,int n){
		int dp[][]=new int[m+1][n+1];//有效下标从1开始
		for(int i=0;i<=m;i++) dp[i][0]=0;
		for(int i=0;i<=n;i++) dp[0][i]=0;
		for(int i=1;i<=m;i++){
			for(int j=1;j<=n;j++){
				for(int k=0;k<=j;k++)
				dp[i][j]=Math.max(dp[i][j], 
						dp[i-1][k]+v[i][j-k]);//前i个公司用了k台机器,则第i个公司可以用j-k台机器
			}
		}
		return dp[m][n];
	}
	

}

 

 

 

二、01背包问题

 

 

 

1.问题引入:

有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?
2.思路分析:
nameweightvalue12345678910
a26066991212151515
b23033669991011
c65000666661011
d54000666661010
e460006666666
 

 

通过找规律手工填写出上面这张表就能理解背包的动态规划算法了。状态转移方程为:

 

f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ),//表示第i件物品放入

 f[i-1,j] //表示第i件物品不放入}

 

首先要明确这张表是至底向上,从左到右生成的。

为了叙述方便,用e2单元格表示e行2列的单元格,这个单元格的意义是用来表示只有物品e时,有个承重为2的背包,那么这个背包的最大价值是0,因为e物品的重量是4,背包装不了。

对于d2单元格,表示只有物品e,d时,承重为2的背包,所能装入的最大价值,仍然是0,因为物品e,d都不是这个背包能装的。

同理,c2=0,b2=3,a2=6。

对于承重为8的背包,a8=15,是怎么得出的呢?

在这里,

 f[i-1,j]表示我有一个承重为8的背包,当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值

f[i-1,j-Wi]表示我有一个承重为6的背包(等于当前背包承重减去物品a的重量),当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值

f[i-1,j-Wi]就是指单元格b6,值为9,Pi指的是a物品的价值,即6

由于f[i-1,j-Wi]+Pi = 9 + 6 = 15 大于f[i-1,j] = 9,所以物品a应该放入承重为8的背包

3.代码如下:
[java]  view plain  copy
 
 
  1. <span style="color:#330099;">package 动态规划资源问题;  
  2.   
  3. public class 01背包问题 {  
  4.     public static void main(String args[]){  
  5.         int v[]={6,3,5,4,6};  
  6.         int w[]={2,2,6,5,4};  
  7.         int c=10;  
  8.         int max=fun(v,w,5,c);  
  9.         System.out.println(max);  
  10.     }  
  11.     public static int fun(int v[],int w[],int i,int wi){  
  12.         int dp[][]=new int[i+1][wi+1];//一维可从0取到i,二维可从0取到wi  
  13.         for(int x=0;x<=i;x++)//无重量,不管有多少件物品,价值都是0  
  14.             dp[x][0]=0;  
  15.         for(int x=0;x<=wi;x++)//没有物品,不管重量多少,价值都是0  
  16.             dp[0][x]=0;  
  17.         for(int x=1;x<=i;x++){  
  18.             for(int y=1;y<=wi;y++){  
  19.                 if(y>=w[x-1]){  
  20.                 dp[x][y]=Math.max(dp[x-1][y], v[x-1]+dp[x-1][y-w[x-1]]);  
  21.                 }else{  
  22.                     dp[x][y]=dp[x-1][y];  
  23.                 }  
  24.             }  
  25.         }  
  26.         return dp[i][wi];  
  27.     }  
  28.   
  29. }</span>  
输出15

三、完全背包问题
1.问题引入

有N种物品和一个重量为V的背包,每种物品都有无限件可用。第i种物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包重量,且价值总和最大。

2.思路分析

类似于01背包问题的解法,01背包问题设二维数组是因为每种物品只有一个,所以i从第一个物品开始往后遍历,而现在物品的个数是无限的,所以运用动态规划的思想,相关变量就是背包的重量了,我们可以设一个一维数组dp[i]表示背包重量为i时得到的最大价值。当背包重量为i时,从第一个物品开始往后遍历,第j个物品最多可以取 i/w[j] 个,那么dp[i]就等于Max { dp[i-k*w[j]]+k*v[j]) }。

3.代码如下

<span style="color:#330099">package 动态规划资源问题;

public class 完全背包问题 {
	public static void main(String args[]){
		int v[]={6,3,5,4,6};  
        int w[]={2,2,6,5,4};  
        int c=10;  
        int max= fun(v,w,5,c);  
       System.out.println(max); 
	}
	public static int fun(int v[],int w[],int n,int c){
		int dp[]=new int[c+1];
		dp[0]=0;//背包无重量
		for(int i=1;i<=c;i++){
			for(int j=0;j<n;j++){//对每种物品遍历
				int m=i/w[j];  //该种物品最多可以放m个
				for(int k=0;k<=m;k++){
					if(i>=w[j]*k)//还能装
						dp[i]=Math.max(dp[i],
								dp[i-k*w[j]]+k*v[j]);
				}
				
			}
			System.out.println(i+" "+dp[i]);
		}
		return dp[c];
	}

}</span>


 
实验课程:算法分析与设计 实验名称:用动态规划法求解资源分配问题 (验证型实验) 实验目标: (1)掌握用动态规划方法求解实际问题的基本思路。 (2)进一步理解动态规划方法的实质,巩固设计动态规划算法的基本步骤。 实验任务: (1)设计动态规划算法求解资源分配问题,给出算法的非形式描述。 (2) 在Windows环境下用C 语言实现该算法。计算10个实例,每个实例中n=30, m=10, Ci j为随机产生于范围(0,103)内的整数。记录各实例的数据及执行结果(即最优分配方案、最优分配方案的值)、运行时间。 (3)从理论上分析算法的时间和空间复杂度,并由此解释相应的实验结果。 实验设备及环境: PC;C/C++等编程语言。 实验主要步骤: (1) 根据实验目标,明确实验的具体任务; (2) 分析资源分配问题,获得计算其最优值的递推计算公式; (3) 设计求解问题动态规划算法,并编写程序实现算法; (4) 设计实验数据并运行程序、记录运行的结果; (5) 分析算法的时间和空间复杂度,并由此解释释相应的实验结果; 问题分析: 问题描述: 某厂根据计划安排,拟将n台相同的设备分配给m个车间,各车间获得这种设备后,可以为国家提供盈利Ci j(i台设备提供给j号车间将得到的利润,1≤i≤n,1≤j≤m) 。问如何分配,才使国家得到最大的盈利? 算法基本思想: 本问题是一简单资源分配问题,由于具有明显的最优子结构,故可以使用动态规划求解,用状态量f[i][j]表示用i台设备分配给前j个车间的最大获利,那么显然有f[i][j] = max{ f[k][j–1] + c[i-k][j] },0<=k<=i。再用p[i][j]表示获得最优解时第j号车间使用的设备数为i-p[i][j],于是从结果倒推往回求即可得到分配方案。程序实现时使用顺推,先枚举车间数,再枚举设备数,再枚举状态转移时用到的设备数,简单3重for循环语句即可完成。时间复杂度为O(n^2*m),空间复杂度为O(n*m),倘若此题只需求最大获利而不必求方案,则状态量可以减少一维,空间复杂度优化为O(n)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w_t_y_y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值