题目链接:https://www.acwing.com/problem/content/167/
题意:将n只小猫,分成重量不超过m的组别,问最少要分成多少组。
本题用到了:可行性剪枝,最优性剪枝,顺序剪枝
#include<bits/stdc++.h>
using namespace std;
const int N=20;
int n,m,ans=N;
int sum[N],w[N];
void dfs(int k,int u)
{
if(u>=ans)return;//最优性剪枝
if(k==n+1)//记得因该搜索到n+1成,这样才是将所有的情况搜索到了
{
ans=u;
return;
}
for(int i=1;i<=u;i++)
{
if(sum[i]+w[k]<=m)//可行性剪枝
{
sum[i]+=w[k];
dfs(k+1,u);
sum[i]-=w[k];//记得回溯的时候要恢复到原来的情况
}
}
//新开一辆车
sum[u+1]=w[k];
dfs(k+1,u+1);
sum[u+1]=0;//记得回溯的时候要恢复到原来的情况
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>w[i];
sort(w+1,w+1+n);//搜索顺序优化
reverse(w+1,w+1+n);//搜索顺序优化
dfs(1,1);
cout<<ans<<endl;
return 0;
}
搜索的时候,一定要记得先搜分支较少的分支记搜索顺序优化,也就是要从分支较少的先搜。这题我们可以先将重量大的猫先放,这样就可以尽量将车占满,这样其他的猫就不能放到该车了,这样我们就可以少搜索很多的情况。如果是小猫先放,那么就会有很多猫可以和他一起放到该车,对于和他放到一起的那只猫,就多了一种搜索情况。而且一定要想清楚搜索顺序一定要所有情况都搜索到。
题目链接:https://www.acwing.com/problem/content/168/
题意:填一个9*9的方格数独
用到了 **优化搜索顺序 和 可行性剪枝
#include<bits/stdc++.h>
using namespace std;
const int N=9,M=1<<N;
int ones[M],Map[M];
int row[N],clos[N],cell[3][3];
char s[100];
void draw(int x,int y,int t,bool is_set)
{
if(is_set)s[x*N+y]='1'+t;
else s[x*N+y]='.';
int v=1<<t;
if(!is_set)v=-v;
row[x]-=v;
clos[y]-=v;
cell[x/3][y/3]-=v;
}
int lowbit(int x)
{
return x&(-x);
}
int get(int x,int y)
{
return row[x]&clos[y]&cell[x/3][y/3];
}
int init()
{
int cnt=0;
for(int i=0;i<N;i++)
{
row[i]=(1<<N)-1;
clos[i]=(1<<N)-1;
}
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
cell[i][j]=(1<<N)-1;
}
}
for(int i=0,k=0;i<N;i++)
{
for(int j=0;j<N;j++,k++)
{
if(s[k]!='.')
{
draw(i,j,s[k]-'1',true);
}
else cnt++;
}
}
return cnt;
}
//cnt表示还有多少个方格没填
bool dfs(int cnt)
{
if(cnt==0)return true;
int minv=10;
int x,y;
//为了将分支最少的点先搜,这样可以节省很多时间
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
if(s[i*N+j]=='.')
{
int state=get(i,j);
if(ones[state]<minv)
{
minv=ones[state];//找到那个可以选择的数最少的空格
x=i,y=j;
}
}
}
}
for(int i=get(x,y);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=i;j;j-=lowbit(j))
{
ones[i]+=1;
}
}
while(cin>>s,s[0]!='e')
{
int k=init();
dfs(k);
puts(s);
}
return 0;
}
题目链接:https://www.acwing.com/problem/content/description/169/
题意:让你将一组数分成若干组,是每组的和相同,让你求每组和的最小值
#include<bits/stdc++.h>
using namespace std;
const int N=70;
int w[N],length,sum;
int n;
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);
//冗余剪枝,我们自己规定了搜索顺序,因为组成木棒的木棍顺序并不影响结果
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;
//s=0说明第一根木棒组成失败了,那么我们就不能通过我们有的小木棍组成长度维length的长木棍
if(s==0)return false;
//
if(s+w[i]==length)return false;
//如果当前位置放长度维w[i]的木棍失败了,那么后面再在该位置放长度和w[i]一样长的木棒也是一样会失败的
int j=i;
while(j<n&&w[i]==w[j])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];
}
//搜索顺序优化,从大到小搜索
sort(w,w+n);
reverse(w,w+n);
length=1;
while(true)
{
if(sum%length==0&&dfs(0,0,0))
{
cout<<length<<endl;
break;
}
length++;
}
}
return 0;
}
思路:因为组成木棒的木棍顺序并不影响结果。所以木棒内的木棍,我们可以随便安排顺序,就规定长度大的排在前面吧,这符合我们的搜索顺序优化。因为如果一根小木棒够长,就可以占据更多的长木棒,这样该木棒的组成情况就会少点了,减少了我们搜索的分支了。
相关剪枝证明题解:https://www.acwing.com/solution/content/121003/
题目acwing池塘计数
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int>PII;
const int N=1010,M=N*N;
int n,m;
char g[N][N];
PII q[M];
bool st[N][N]; //state状态的缩写,初始都是false
void bfs(int sx,int sy)
{
int hh=0,tt=0;//hh表示队头,tt表示队尾
q[0]={sx,sy};//***********
st[sx][sy]=true;
while(hh<=tt)
{
PII t=q[hh++];//表示从队头将该元素删掉
for(int i=t.x-1;i<=t.x+1;i++)
{
for(int j=t.y;j<=t.y+1;j++)
{
if(i==t.x&&j==t.y)continue;//遍历走遍相连的八个格子,可以用两个for循环,将中间那个点去掉即可
if(i<0||i>=n||j<0||j>=m)continue;//越界的情况
if(g[i][j]=='.'||st[i][j])continue;
q[++t]={i,j};
st[i][j]=true;
}
}
}
}
int main()
{
//因为输入可能超过100万了,所以用scanf好点
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)scanf("%s",g[i]);//直接用首地址进行读入
int cnt=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
if(g[i][j]=='W'&&!st[i][j])
{
bfs(i,j);//进行填充
cnt++;
}
}
printf("%d",cnt);
return 0;
}
题目:城堡问题
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int>PII;
const int N=55,M=N*N;
int n,m;
char g[N][N];
PII q[M];
bool st[N][N]; //state
int dx[4]={0,-1,0,1},dy[4]={-1,0,1,0};
int bfs(int sx,int sy)
{
int hh=0,tt=0;
int area=0;
q[0]={sx,sy};
st[sx][sy]=true;
while(hh<=tt)
{
PII t=q[hh++];
area++;
for(int i=0;i<4;i++)
{
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||a>=n||b<0||b>=n)continue;
if(st[a][b])continue;
if((g[t.x][t.y]>>1)&1)continue;
q[++tt]={a,b};
st[a][b]=true;
}
}
return area;
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)cin>>g[i][j];
}
int cnt=0,area=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
if(!st[i][j])
{
area=max(area,bfs(i,j));
cnt++;
}
}
cout<<cnt<<endl;
cout<<area<<endl;
return 0;
}
题目链接:https://www.dotcpp.com/oj/problem2365.html
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int>PII;
const int N=1010,M=N*N;
int h[N][N];
int n;
PII q[M];
bool st[N][N];
void bfs(int sx,int sy,bool &has_higher,bool &has_lower)
{
int hh=0,tt=0;
q[0]={sx,sy};
st[sx][sy]=true;
while(hh<=tt)
{
PII t=q[hh++];
for(int i=t.x-1;i<=t.x+1;i++)
for(int j=t.y-1;j<=t.y+1;j++)
{
if(i<0||i>=n||j<0||j>=n)continue;
if(h[i][j]!=h[t.x][t.y])
{
if(h[i][j]>h[t.x][t.y])has_higher=true;
else has_lower=true;
}
else if(!st[i][j]){
q[++tt]={i,j};
st[i][j]=true;
}
}
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&h[i][j]);
int peak=0,valley=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(!st[i][j])
{
bool has_higher=false,has_lower=false;
bfs(i,j,has_higher,has_lower);
if(!has_higher)peak++;
if(!has_lower)valley++;
}
}
printf("%d %d\n",peak,valley);
return 0;
}
题目链接:https://www.dotcpp.com/oj/problem2178.html
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int>PII;
const int N=1010,M=N*N;
int g[N][N];
int n;
PII q[M];
PII pre[N][N];
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
void bfs(int sx,int sy)
{
int hh=0,tt=0;
q[0]={sx,sy};
memset(pre,-1,sizeof(pre));
pre[sx][sy]={0,0};
while(hh<=tt)
{
PII t=q[hh++];
for(int i=0;i<4;i++)
{
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||a>=n||b<0||b>=n)continue;
if(g[a][b])continue;
if(pre[a][b].x!=-1)continue;
q[++tt]={a,b};
pre[a][b]=t;
}
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
scanf("%d",&g[i][j]);
}
bfs(n-1,n-1);
PII END={0,0};
while(true)
{
printf("(%d, %d)\n",END.x,END.y);
if(END.x==n-1&&END.y==n-1)break;
END=pre[END.x][END.y];
}
return 0;
}
题目链接:https://www.acwing.com/problem/content/190/
#include<bits/stdc++.h>
using namespace std;
const int N=155,M=N*N;
typedef pair<int,int> PII;
PII q[M];
int dis[N][N];
char g[N][N];
int n,m;
int bfs()
{
int dx[]={-2,-1,1,2,2,1,-1,-2};
int dy[]={1,2,2,1,-1,-2,-2,-1};
int sx,sy;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
if(g[i][j]=='K')
sx=i,sy=j;
}
int tt=0,hh=0;
q[0]={sx,sy};
memset(dis,-1,sizeof dis);
dis[sx][sy]=0;
while(hh<=tt)
{
PII t=q[hh++];
for(int i=0;i<8;i++)
{
int a=t.first+dx[i] ,b=t.second+dy[i];
if(a<0||a>=n||b<0||b>=m)continue;
if(g[a][b]=='*')continue;
if(dis[a][b]!=-1)continue;
if(g[a][b]=='H')return dis[t.first][t.second]+1;
dis[a][b]=dis[t.first][t.second]+1;
q[++tt]={a,b};
}
}
return -1;
}
int main()
{
cin>>m>>n;
for(int i=0;i<n;i++)cin>>g[i];
cout<<bfs()<<endl;
return 0;
}