P2392 kkksc03考前临时抱佛脚【搜索】

在这里插入图片描述
在这里插入图片描述

1 :5
2 :43
3:6
4:243

回溯

博主:https://glgjssy-qyhfbqz.blog.luogu.org/solution-p2392

数据范围20?emmm

于是放心大胆地2^n枚举了

枚举每道题交给哪边的脑子解决,找到两边时间较大值的最小值

于是愉快地解决了……剪枝都不用放

#include<iostream>
using namespace std;
int Left,Right,minn,ans;
int s[5];//存科目的数量 
int a[21][5];//存科目题目的时间 

void search(int x,int y){//从第 x 题开始,第 y 个学科  
	if(x>s[y]) //题目大于学科题目总数    //循环结束 
	{
		minn=min(minn,max(Left,Right));
		return;
	}
	Left+=a[x][y];
	search(x+1,y);
	Left-=a[x][y];
	Right+=a[x][y];
	search(x+1,y);
	Right-=a[x][y];//毫无技巧的搜索回溯
}
int main(){
	cin>>s[1]>>s[2]>>s[3]>>s[4];//4科的数量 
	for(int i=1;i<=4;i++)
	{
		Left=Right=0;//左脑右脑都为0 
		minn=19260817;//最小值 
		for(int j=1;j<=s[i];j++)//便利每科的耗时 
			cin>>a[j][i];//科目i的第j个题的耗时 
		search(1,i);//一科一科的复习,从第一个题开始,第i个学科 
		ans+=minn;
	} 
	cout<<ans;
	return 0;
}

在这里插入图片描述
在这里插入图片描述

01背包

博主:https://www.luogu.com.cn/blog/acxblogs/solution-p2392

四个科目其实就是四组数据。考虑一个科目单独分析。
显然若当前要处理的问题的时间和为t,最佳答案是t/2,也就是两边脑所耗时间差为0。
于是现在要求的问题就是使得两边脑所耗时间差尽量小。

于是我想到了二分,胡乱分析一番,想不出来先放一边。进一步分析。
如果只考虑一边脑耗时,由于两边脑是对称的,我们假设这个耗时肯定比t/2小。那么我们要使这个耗时尽量接近t/2。
然后又想到了背包。保证比t/2小,又要使取得的价值尽量大,可以转化为一个费用与价值相同的背包问题。背包大小为t/2,一个题目的费用和价值相等,都是所耗的时间。
假设背包求得的最大价值为v,显然另一个脑耗时为t-v,则总耗时为max(v,t-v)。
四组数据按照相同方法处理。

对于一道题只有两个状态,一是加到左脑,二是加到右脑,所以是01背包

有N件物品和一个容量为V的背包。第i件物品的体积是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大

for (i = 1; i <= n; i++)
    for (j = v; j >= c[i]; j--)//在这里,背包放入物品后,容量不断的减少,直到再也放不进了
        f[i][j] = max(f[i - 1][j], f[i - 1][j - c[i]] + w[i]);
#include<bits/stdc++.h>
using namespace std;

int len[4];//存每科题目总数  从0开始 
int sub[30];//每题的时间     从1开始 
int f[21][1201];

int main(){
	for(int i=0;i<4;i++)cin>>len[i];
	int tot=0;//所有学科总时间 
	for(int i=0;i<4;i++){//遍历学科 
		int v=0;//单个学科总时间 
		for(int j=1;j<=len[i];j++) cin>>sub[j],v+=sub[j];
        sort(sub,sub+len[i]);//每题时间 从小到大排序 
        int t1=0;
        //01背包:   个数   容量 
        for(int j=1;j<=len[i];j++)//j题号 
            for(int k=0;k<=v/2;k++){//半个背包的容量 
//            	f[j][k]=max(f[j-1][k],f[j-1][k-sub[j]]+sub[j]);
                f[j][k]=f[j-1][k]; 
                if(k>=sub[j])
					f[j][k]=max(f[j][k],f[j-1][k-sub[j]]+sub[j]);
                t1=max(f[j][k],t1);
            }
        tot+=max(t1,v-t1);
	} 
	cout<<tot<<endl;
	return 0; 
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

DDouble-

你的鼓励是我最大的动力~

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

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

打赏作者

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

抵扣说明:

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

余额充值