#写在前面
#DFS之剪枝与优化
##小猫爬山
https://www.acwing.com/problem/content/167/
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
//1.优先放重猫
//2.可行性减枝
//3.最优性剪枝
using namespace std;
const int N=20;
int n, m;
int w[N];
int sum[N];
int ans=N;
void dfs(int u, int k){
//3.
if(k>=ans)return;
if(u==n){
ans=k;
return;
}
for(int i=0; i<k; i++)
if(sum[i]+w[u]<=m){//2.
sum[i]+=w[u];
dfs(u+1, k);
sum[i]-=w[u];
}
sum[k]=w[u];
dfs(u+1, k+1);
sum[k]=0;
}
int main(){
cin>>n>>m;
for(int i=0; i<n; i++) cin>>w[i];
//1
sort(w, w+n);
reverse(w, w+n);
dfs(0, 0);
cout<<ans<<endl;
return 0;
}
##数独
https://www.acwing.com/problem/content/168/
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=9, M=1<<N;;
int ones[M];//存一个数里有几个1;
int map[M];//快速求出2的几次方log一下是多少
int row[N], col[N], cell[3][3];
char str[100];
void init(){
for(int i=0; i<N; i++) row[i]=col[i]=(1<<N)-1;
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
cell[i][j]=(1<<N)-1;
}
void draw(int x, int y, int t, bool is_set){//填数字的函数
if(is_set) str[x*N+y]='1'+t;
else str[x*N+y]='.';
int v=1<<t;
if(!is_set)v=-v;
row[x]-=v;
col[y]-=v;
cell[x/3][y/3]-=v;
}
int lowbit(int x){
return x&-x;
}
int get(int x, int y){//求x,y上能填哪些数
return row[x]&col[y]&cell[x/3][y/3];
}
bool dfs(int cnt){
if(!cnt) return true;
int minv=10;
int x,y;//找一个分支数量最少的空格
for(int i=0; i<N; i++)
for(int j=0; j<N; j++)
if(str[i*N+j]=='.'){
int state=get(i, j);
if(ones[state]<minv){
minv=ones[state];
x=i,y=j;
}
}
int state=get(x,y);
for(int i=state; i; i-=lowbit(i)){
int t=map[lowbit(i)];
draw(x,y,t,true);
if(dfs(cnt-1))return true;
draw(x,y,t,false);
}
return false;
}
int main(){
for(int i=0; i<N; i++) map[1<<i]=i;
for(int i=0; i<M; i++)
for(int j=0; j<N; j++)
ones[i]+= i>>j&1;
while(cin>>str, str[0]!='e'){
init();
int cnt=0;
for(int i=0, k=0; i<N; i++)
for(int j=0; j<N; j++, k++)
if(str[k]!='.'){
int t=str[k]-'1';
draw(i, j, t, true);
}
else cnt++;
dfs(cnt);
puts(str);
}
return 0;
}
##木棒
https://www.acwing.com/problem/content/169/
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=70;
int n;
int w[N], sum, length;
bool st[N];
bool dfs(int u, int s, int start){
if(u*length == sum)return true;
if(s==length)return dfs(u+1, 0, 0);
//剪枝3-1
for(int i=start; i<n; i++){
if(st[i])continue;
if(s+w[i]>length)continue;//可行性剪枝
st[i]=true;
if(dfs(u, s+w[i], i+1))return true;
st[i]=false;
//剪枝3-3
if(!s)return false;
//剪枝3-4
if(s+w[i]==length)return false;
//剪枝3-2
int j=i;
while(j<n&&w[j]==w[i])j++;
i=j-1;
}
return false;
}
int main(){
while(cin>>n, n){
memset(st, 0, sizeof st);
sum=0;
for(int i=0; i<n; i++){
cin>>w[i];
sum+=w[i];
}
//剪枝2
sort(w, w+n);
reverse(w, w+n);
length=1;
while(true){
//剪枝1
if( sum % length == 0 && dfs(0, 0, 0)){
cout<<length<<endl;
break;
}
length++;
if(length>sum)break;
}
}
return 0;
}
##生日蛋糕
https://www.acwing.com/problem/content/170/
稍后会补上详解
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=25, inf=1e9;
int n,m;
int minv[N], mins[N];
int R[N], H[N];
int ans=inf;
void dfs(int u, int v, int s){
if(v+minv[u]>n)return;
if(s+mins[u]>=ans)return;
if(s+2*(n-v)/R[u+1]>=ans)return;
if(!u){
if(v==n)ans=s;
return;
}
for(int r=min(R[u+1]-1, (int)sqrt(n-v)); r>=u; r--)
for(int h=min(H[u+1]-1, (n-v)/r/r); h>=u; h--){
int t=0;
if(u==m)t=r*r;
R[u]=r, H[u]=h;
dfs(u-1, v+r*r*h, s+2*r*h+t);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
minv[i]=minv[i-1]+i*i*i;
mins[i]=mins[i-1]+2*i*i;
}
R[m+1]=H[m+1]=inf;
dfs(m, 0, 0);
if(ans==inf)ans=0;
cout<<ans<<endl;
return 0;
}