191101苦练搜索

震惊!ZJ某中苦练搜索暴力出奇迹
敲黑板敲黑板敲黑板
关于搜索剪枝的一点思考
剪枝的两个角度
1 最大限制:超过了最大限制一定不优
2 最优答案:如果剩下的所有(剩余的量)都加上,还达不到(不一定是大)目前最优的答案,那么一定不优

还要建立一个习惯——预估M和T会不会超
常见数据范围:
搜索——n<100
DP——n>100&&n<10000
高级的算法,二分之类(带log)——n>100000

T1 transq

可以用状压的思想
不过为了苦练搜索,我们采用这种方式

在这里插入图片描述
审题啊!一个实数卡我半个小时
一眼望去背包DP
有实数!!!
于是读优GG,DPGG
可以用状压的思想
可以回溯

最劣情况:每一种都搜一下
O ( 2 N ) 2 30 > 1 0 8 O(2^N)\Rightarrow 2^{30}>10^8
因此必须剪枝
优化1:目前重量>最大载重,return;
优化2:当前总val+剩下所有val倒序求’后缀和’<ans(目前求出的最优答案),return;

代码如下

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
#define NNN 100
int n;
double w[NNN],v[NNN],ans,f[NNN],x;
bool exist[NNN],best[NNN];

//inline int in{
//	int i=0,f=1;char ch;
//	while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
//	if(ch=='-'){
//		ch=getchar();f=-1;
//	}
//	while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
//	return i*f;
//}

inline void Dfs(int step,double wei,double val){
	if(wei>x)return;//¼ôÖ¦1 
	
	if(step>n)
		if(val>ans){
			ans=val;
			for(re int i=1;i<=n;i++)
				best[i]=exist[i];
			return ;//СÐÄŶ~ ±ß½çÌõ¼þµÄ¹Ø¼ü¾ÍÊÇreturn 
		}
	
	if(val+f[step]<ans)return;//¼ôÖ¦2 
	
	exist[step]=true;
	Dfs(step+1,wei+w[step],val+v[step]);
	exist[step]=false;
	Dfs(step+1,wei,val);
	return ;
}

int main(){
	scanf("%lf%d",&x,&n);
	for(re int i=1;i<=n;i++)scanf("%lf%lf",&w[i],&v[i]);
	
	for(re int i=n;i>=1;i--)f[i]=f[i+1]+v[i];//Ô¤´¦Àí:ºó׺ºÍ 
	
	Dfs(1,0,0);
	
	printf("%d\n",(int)ans);
	for(re int i=1;i<=n;i++)
		if(best[i])
			printf("%d ",i);
	
	return 0;
}

T2 dispatch

在这里插入图片描述
不管那么多,直接考虑优化

优化1: 最大限制
优化2: 从大到小排序, 筛去无效分支(有点类似于贪心)
优化3: 最优答案

小心time的关键词冲突

代码如下

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
#define INF 2147483647
int n,k,ans=INF;
int t[20],Time[10];

inline int in{
	int i=0,f=1;
	char ch;
	for(ch=getchar();(ch>'9'||ch<'0')&&ch!='-';ch=getchar());
	if(ch=='-'){
		ch=getchar();f=-1;
	}
	for(;ch>='0'&&ch<='9';ch=getchar())i=ch-48+(i<<1)+(i<<3);
	return f*i;
}

inline bool comp(const int &a,const int &b){
	return a>b;
}

inline void Dfs(int step,int maxt){
	if(maxt>=ans)return ;
	
	if(step>n){
		//已经把>ans的情况剪掉了,不需要再比较就可以直接更新答案
		ans=maxt;
		return ; 
	}
	
	for(re int i=1;i<=k;i++){
		if(Time[i]+t[step]>ans)continue ;//又一个剪枝 小心不是return哦~ 
		Time[i]+=t[step];
		Dfs(step+1,max(maxt,Time[i]));//以最久的时间为准
		Time[i]-=t[step];//要取消
	}
	return ;
}

int main(){
	n=in,k=in;
	for(re int i=1;i<=n;i++)t[i]=in;
	
	sort(t+1,t+n+1,comp);
	
	Dfs(1,0);
	
	printf("%d",ans);
	return 0;
}
发布了26 篇原创文章 · 获赞 3 · 访问量 913

猜你喜欢

转载自blog.csdn.net/Antimonysbguy/article/details/102865122