搜索好题记录

题目链接: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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值