1,dfs剪枝优化:eg1:acwing 165. 小猫爬山;eg2:数独; 2,blocks;3,Sleeping in Class;
1,dfs剪枝优化:
优化策略通常如下:
①优化搜索顺序:大部分情况应该搜索分支少的节点;
②排除等效冗余:尽量不搜索重复的状态;(不考虑顺序的时候,用组合的方式去搜索);
③可行性剪枝:不满足题目要求的分支直接剪掉;
④最优性剪枝:如果当前状态的出的答案一定比已经得到的答案不优,也直接剪掉;
eg1:小猫爬山;
题意:
剪枝策略放代码注释:
优化搜索顺序可以理解一下:优先放重的猫,最有可能把当前的车放满从而减小分支;
(记得之前做oj一道训练题,就差优化搜索顺序给tle了);
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rep1(i,a,n) for(register int i=a;i<n;++i)
#define rep2(i,a,n) for(register int i=a;i<=n;++i)
#define per1(i,n,a) for(register int i=n;i>a;i--)
#define per2(i,n,a) for(register int i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i) memset((a),(i),sizeof (a))
#define memcpy(a,i) memcpy((a),(i),sizeof (a))
#define pro_q priority_queue
#define pb push_back
#define pf push_front
#define endl "\n"
#define lowbit(m) (-m&m)
#define YES cout<<"YES\n"
#define NO cout<<"NO\n"
#define Yes cout<<"Yes\n"
#define No cout<<"No\n"
#define yes cout<<"yes\n"
#define no cout<<"no\n"
#define yi first
#define er second
using namespace std;
typedef pair<int,int> PII;
typedef pair<long long,long long>PLL;
typedef pair<int,PII> PIII;
typedef long long ll;
typedef double dob;
const int N=20;
int w[N],sum[N],n,m;
int ans=N;
void dfs(int u,int k)
{
if(k>=ans)return ;//最优性剪枝
if(u==n)
{
ans=k;
return ;
}
rep1(i,0,k)
{
if(sum[i]+w[u]<=m)//可行性剪枝
{
sum[i]+=w[u];
dfs(u+1,k);
sum[i]-=w[u];//恢复现场
}
}
sum[k]=w[u];//新开一辆车
dfs(u+1,k+1);
sum[k]=0;//恢复现场
}
signed main()
{
quick_cin();
cin>>n>>m;
rep1(i,0,n)cin>>w[i];
sort(w,w+n,greater<int>());//优化搜索顺序
dfs(0,0);
cout<<ans;
return 0;
}
eg2:数独;
题意:
思路很暴力简单,就是有空的地方找符合条件的数填;
剪枝优化策略:
①优化搜索顺序,填的时候选择分支最少的格子;
②可行性剪枝:只能填满足条件的数字;
还有其他的优化细节:
用长度为9的01串来表示1~9中的数字哪个可以用(当前位置为1即可用,类似状态压缩);
所以求01串的1的位置,不要9个循环一次,用lowbit操作逐个取1(小优化);
求可以填哪个数的时候,就是求行,列,九宫格的01串的交集的1,即hang&lie&cell;
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rep1(i,a,n) for(register int i=a;i<n;++i)
#define rep2(i,a,n) for(register int i=a;i<=n;++i)
#define per1(i,n,a) for(register int i=n;i>a;i--)
#define per2(i,n,a) for(register int i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i) memset((a),(i),sizeof (a))
#define memcpy(a,i) memcpy((a),(i),sizeof (a))
#define pro_q priority_queue
#define pb push_back
#define pf push_front
#define endl "\n"
#define lowbit(m) ((-m)&(m))
#define YES cout<<"YES\n"
#define NO cout<<"NO\n"
#define Yes cout<<"Yes\n"
#define No cout<<"No\n"
#define yes cout<<"yes\n"
#define no cout<<"no\n"
#define yi first
#define er second
using namespace std;
typedef pair<int,int> PII;
typedef pair<long long,long long>PLL;
typedef pair<int,PII> PIII;
typedef long long ll;
typedef double dob;
const int N=10,M=1<<N;
int hs[M];
int ones[M],col[N],row[N],cell[3][3];
char s[M];
int get(int x,int y)
{
return row[x]&col[y]&cell[x/3][y/3];
}
void init()
{
rep1(i,0,9)row[i]=col[i]=(1<<9)-1;
rep1(i,0,3)
rep1(j,0,3)
cell[i][j]=(1<<9)-1;
}
void draw(int x,int y,int t,bool is_set)
{
if(is_set)s[x*9+y]='1'+t;
else s[x*9+y]='.';
int v=1<<t;
if(!is_set)v=-v;
row[x]-=v;
col[y]-=v;
cell[x/3][y/3]-=v;
}
bool dfs(int cnt)
{
if(!cnt)return 1;
int minv=10;
int x,y;
rep1(i,0,9)
rep1(j,0,9)
if(s[i*9+j]=='.')
{
int state=get(i,j);
if(ones[state]<minv)
{
x=i,y=j;
minv=ones[state];
}
}
int state=get(x,y);
for(int i=state;i;i-=lowbit(i))
{
int t=hs[lowbit(i)];
draw(x,y,t,1);
if(dfs(cnt-1))return 1;
draw(x,y,t,0);
}
return 0;
}
signed main()
{
quick_cin();
rep1(i,0,N)hs[1<<i]=i;
rep1(i,0,M)
rep1(j,0,9)
ones[i]+=i>>j&1;
while(cin>>s,s[0]!='e')
{
init();
int cnt=0;
for(int i=0,k=0;i<9;++i)
{
for(int j=0;j<9;++j,++k)
{
if(s[k]!='.')
{
int t=s[k]-'1';
draw(i,j,t,1);
}
else cnt++;
}
}
dfs(cnt);
cout<<s<<endl;
}
return 0;
}
2,blocks;
题意:
思路:直接在6x4的矩阵里找,4重循环,能够找得到就行;
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rep1(i,a,n) for(register int i=a;i<n;++i)
#define rep2(i,a,n) for(register int i=a;i<=n;++i)
#define per1(i,n,a) for(register int i=n;i>a;i--)
#define per2(i,n,a) for(register int i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i) memset((a),(i),sizeof (a))
#define memcpy(a,i) memcpy((a),(i),sizeof (a))
#define pro_q priority_queue
#define pb push_back
#define pf push_front
#define endl "\n"
#define lowbit(m) (-m&m)
#define YES cout<<"YES\n"
#define NO cout<<"NO\n"
#define Yes cout<<"Yes\n"
#define No cout<<"No\n"
#define yes cout<<"yes\n"
#define no cout<<"no\n"
#define yi first
#define er second
using namespace std;
typedef pair<int,int> PII;
typedef pair<long long,long long>PLL;
typedef pair<int,PII> PIII;
typedef long long ll;
typedef double dob;
const int N=1e5+10;
string s[10];
int n;
string word;
void solve()
{
cin>>word;
unordered_map<char,int>hs1;
unordered_map<char,int>hs2;
rep1(i,0,word.size())
hs1[word[i]]++;
rep1(i,0,6)
rep1(j,0,6)
rep1(k,0,6)
rep1(m,0,6)
{
hs2.clear();
hs2[s[0][i]]++;
hs2[s[1][j]]++;
hs2[s[2][k]]++;
hs2[s[3][m]]++;
int len=0;
while(hs1[word[len]]==hs2[word[len]])
{
len++;
if(len==word.size())
{
YES;
return;
}
}
}
NO;
}
signed main()
{
quick_cin();
cin>>n;
rep1(i,0,4)cin>>s[i];
while(n--)solve();
return 0;
}
3,sleeping in class;
题意:给你一个数组,你可以将这个数组中的相邻两个数替换为它们的和,设这样为 1 次操作,则进行多少次操作后,数组中所有的数相等。输出最小的操作次数;
因为最终是数组中数都等于一个值,所以可以枚举该值;
一个有sum/x个数,所以合并了n-sum/x次;
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rep1(i,a,n) for(register int i=a;i<n;++i)
#define rep2(i,a,n) for(register int i=a;i<=n;++i)
#define per1(i,n,a) for(register int i=n;i>a;i--)
#define per2(i,n,a) for(register int i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i) memset((a),(i),sizeof (a))
#define memcpy(a,i) memcpy((a),(i),sizeof (a))
#define pro_q priority_queue
#define pb push_back
#define pf push_front
#define endl "\n"
#define lowbit(m) (-m&m)
#define YES cout<<"YES\n"
#define NO cout<<"NO\n"
#define Yes cout<<"Yes\n"
#define No cout<<"No\n"
#define yes cout<<"yes\n"
#define no cout<<"no\n"
#define yi first
#define er second
using namespace std;
typedef pair<int,int> PII;
typedef pair<long long,long long>PLL;
typedef pair<int,PII> PIII;
typedef long long ll;
typedef double dob;
const int N=1e5+10;
int n;
int a[N];
ll sum;
bool check(int k)
{
if(sum%k)return 0;
ll sum1=0;
rep2(i,1,n)
{
sum1+=a[i];
if(sum1>k)return 0;
sum1%=k;
}
return 1;
}
void solve()
{
cin>>n;
sum=0;
rep2(i,1,n)
{
cin>>a[i];
sum+=a[i];
}
if(!sum)cout<<0<<endl;
else
{
rep2(i,1,sum)
{
if(check(i))
{
cout<<n-sum/i<<endl;
return ;
}
}
}
}
signed main()
{
quick_cin();
int T;cin>>T;
while(T--)solve();
return 0;
}