在组合型枚举中,两种枚举方式有什么区别?
方式1:按照指数型枚举进行,枚举每个数选或不选,再加上可行性剪枝
方式2:枚举每个位置可以填什么数,用一个变量标记下一个要选择的数的下标,避免重复枚举
方式1,2在时间效率上有什么区别?
分别在什么情况下使用?
为什么“小猫爬山”使用方式1可以通过,而方式2会超时?
求解答
小猫爬山1:可以通过
#include<iostream>
#include<algorithm>
#define N 20
using namespace std;
int a[N],v[N],n,m,ans=N;
void dfs(int cat,int car){
if(car>=ans) return ;//剪枝
if(cat==n+1) {//n操作结束,到n+1截止
ans=car;
return ;
}
for(int i=1;i<=car;i++){//从1开始而不是从0开始是因为1缆车才开始放入小猫,直到第car个缆车
if(a[cat]+v[i]<=m){
v[i]+=a[cat];
dfs(cat+1,car);
v[i]-=a[cat];
}
}
v[car+1]=a[cat];
dfs(cat+1,car+1);
v[car+1]=0;
}
int main(){
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> a[i];
sort(a+1,a+n+1);
reverse(a+1,a+n+1);//剪枝
dfs(1,0); //当前为第1只猫,当前为第0辆车(在dfs中直接新建缆车)
cout << ans << endl;
return 0;
}
小猫爬山,方式2,超时
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=25;
int n,m,a[N],cnt[N],car=1,start=1,ans=0x7fffffff,b[N];
void dfs(int c,int s,int cat){
if(c>=ans) return ;
if(cat>n) {
ans=min(ans,c);
return ;
}
int flag=1;
for(int i=s;i<=n;i++){
if(cnt[c]+a[i]<=m&&b[i]==0){
b[i]=1;
cnt[c]+=a[i];
dfs(c,s+1,cat+1);
b[i]=0;
cnt[c]-=a[i];
flag=0;
}
}
if(flag){
dfs(c+1,1,cat);
}
return ;
}
int main(){
cin >> n >> m;
for(int i=1;i<=n;i++){
cin >> a[i];
}
sort(a+1,a+n+1);
reverse(a+1,a+n+1);
dfs(car,start,1);
cout << ans << endl;
return 0;
}