【算法每日一练]-背包类型 篇4 考前临时抱佛脚(两种解法)

今天再继续讲一道多解的题

目录

题目:考前临时抱佛脚

  解法1:背包

  解法2:dfs搜索 


        

          

题目:考前临时抱佛脚

   


   

解法1:背包

思路有点巧劲:因为可以同时处理两个同科的题,那么最优的情况就是恰好耗时总时间的一半,其余的情况都是要多余总时间一半的,那么按照这种思想。我们就放置一个T总/2容量的背包,把每道题的时间当成体积,体积同时也是价值,能塞多少就塞多少,这个背包尽量去留下最少的剩余空间,那么另一半就是最优解了。

   

操作:
不难发现每个题都只有两个状态,要么放入背包要么不放,同时各种题只有一道,裸的01背包。
我们设置dp[i]表示背包容量为i情况下的最优解(也就是能占用空间最多)
转移方程:dp[i]=max(dp[i],dp[i-homework[i]]+homework[i]) (因为体积就是价值)

#include<bits/stdc++.h>                 
using namespace std;  
int a[5],i,j,k,sum,t,homework[21],dp[2501];
int main(){
	for(i=1;i<=4;i++)
		cin>>a[i];
	for(i=1;i<=4;i++){            //一共四科,所以算4个最短时间
		sum=0;	
		for(j=1;j<=a[i];j++){
			cin>>homework[j];	sum+=homework[j];
			}
		for(j=1;j<=a[i];j++)
			for(k=sum/2;k>=homework[j];k--)//背包容量为总时间的一半,找出能装下的最大时间
			dp[k]=max(dp[k],dp[k-homework[j]]+homework[j]);//01背包的状态转移方程

		t+=sum-dp[sum/2];//dp[sum/2]为一半时间的背包最大装下的时间,则sum-dp[sum/2]为最短用时
		for(j=1;j<=sum/2;j++)  dp[j]=0;//清零,计算下一科目
	}
	cout<<t;
	return 0;
}

  


   

 解法2:dfs搜索

设置dfs(l,r,step)  l,r表示左右脑对应的使用时间,step表示当前处理的题数。每当处理完所有的题就开始取左右脑的最值,然后取最小的最值即可。
当然每个dfs都有两个分支,分别是dfs(t[n][step]+l,r,step,n)和dfs(l,t[n][step]+r,step,n);

  
(你可能会问我超时的问题)因为数据最大是2^20次方×4(也就几十万次),而计算机一秒可以运算10^8(一个亿),所以不会超时的

#include <bits/stdc++.h>              
using namespace std;
int s[5],t[5][25],ans=0,mark[5]={0,10000,10000,10000,10000};
void f(int l,int r,int step,int n){     //l,r用于左右相加,step控制递归层数,n控制答案存放位置(mark[n])
	if(step==s[n]){
		int tmp=max(l,r);           //判断所有情况左右脑中的最大值
		if(tmp<mark[n]) mark[n]=tmp;//找最大值中的最小值
		return;
	}
	step++;
	f(t[n][step]+l,r,step,n);      //每道题要么交给左脑要么交给右脑
	f(l,t[n][step]+r,step,n);
}
int main(){
	for(int i=1;i<=4;i++)cin>>s[i];
	for(int i=1;i<=4;i++){
		for(int j=1;j<=s[i];j++)
		  cin>>t[i][j];
	}
	for(int i=1;i<=4;i++){       //计算4科分别最少用时
		f(0,0,0,i);               
	}
	for(int i=1;i<=4;i++){
		ans+=mark[i];
	}
	cout<<ans;
	return 0;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值