搜索专题

1.模拟战役

原题链接:https://ac.nowcoder.com/acm/contest/86654/C

算出敌我的联通块数量和自身联通块包含大炮的数量数列,若我方少于敌方联通块,就返回-1,否则贪心地留下含有较多大炮的联通块并累加

查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int m,ans;
char a[1000][1000];
int sign[1000][1000];
int t,s[1000000],res;
int dx[8]={-1,-1,-1,0,0,1,1,1},dy[8]={-1,0,1,-1,1,-1,0,1};
void bfs1(int x,int y)
{
    sign[x][y]=1;
    for(int i=0;i<8;i++)
    {
        int X=x+dx[i],Y=y+dy[i];
        if(X>=1&&X<=4&&Y>=1&&Y<=m&&a[X][Y]=='*'&&!sign[X][Y])
        {
            bfs1(X,Y);
        }
    }
    return;
}
int bfs2(int x,int y)
{
    ans++;
    sign[x][y]=1;
    for(int i=0;i<8;i++)
    {
        int X=x+dx[i],Y=y+dy[i];
        if(X>=5&&X<=8&&Y>=1&&Y<=m&&a[X][Y]=='*'&&!sign[X][Y])
        {
            bfs1(X,Y);
        }
    }
    return ans;
}
signed  main()
{
    cin>>m;
    for(int i=1;i<=8;i++)
    {
        getchar();
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    for(int i=1;i<=4;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(!sign[i][j]&&a[i][j]=='*')
                t++,bfs1(i,j);
        }
    }
    //cout<<t<<endl;
    for(int i=5;i<=8;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(!sign[i][j]&&a[i][j]=='*')
            {
                s[res++]=bfs2(i,j);
            }
        }
    }
    if(res<t)
    {
        cout<<-1<<endl;
        return 0;
    }
    sort(s,s+res);
    int sum=0;
    for(int i=t+1;i<res;i++)
        sum+=s[i];
    cout<<sum<<endl;
    return 0;
}

2.Jelly

原题链接:https://ac.nowcoder.com/acm/contest/86654/D

三维bfs板板,但是注意起始加一

查看代码
 #include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=110;
char g[N][N][N];
int f[N][N][N];
typedef struct go
{
    int yi;
    int er;
    int san;
}PII;
int n,m;
void bfs()
{
    queue<PII> q;
    q.push({1,1,1});
    memset(f,-1,sizeof f);
    f[1][1][1]=1;
    while(!q.empty())
    {
        PII start = q.front();
        q.pop();
        g[start.yi][start.er][start.san]='*';
        int dx[6]={0,0,0,0,-1,1},dy[6]={0,0,-1,1,0,0},dz[6]={1,-1,0,0,0,0};
        for(int i=0;i<6;i++)
        {
            int x=start.yi+dx[i],y=start.er+dy[i],z=start.san+dz[i];
            if(g[x][y][z]=='.')
            {
                g[x][y][z]='*';
                f[x][y][z]=f[start.yi][start.er][start.san]+1;
                q.push({x,y,z});
            }
        }
    }
    cout<<f[n][n][n];
}
int main()
{
    memset(g,'*',sizeof(g));
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
            cin>>g[i][j][k];
    bfs();
    return 0;
}

3.寻找道路

原题链接:https://ac.nowcoder.com/acm/contest/86654/E

要使路径所有点指向终点,那就从终点倒着遍历,能遍历到就打标,并且将连通着没打上标的点的点去标记,最后正着遍历即可

查看代码
 #include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=200010;
vector<int> v1[N],v2[N];
typedef pair <int ,int>PII;
int n,m,s,t;
int sign[N],vis[N],vis2[N];
void dfs(int x)
{
    sign[x]=1;
    for(int i=0;i<v2[x].size();i++)
    {
        if(!sign[v2[x][i]])
        {
            dfs(v2[x][i]);
        }
    }
}
void bfs()
{
    queue<PII>q;
    q.push({s,0});
    vis[s]=1;
    while(!q.empty())
    {
        PII f=q.front();
        q.pop();
        if(f.first==t)
        {
            cout<<f.second<<endl;
            return;
        }
        for(int i=0;i<v1[f.first].size();i++)
        {
            if(!vis[v1[f.first][i]]&&vis2[v1[f.first][i]])
            {
                vis[v1[f.first][i]]=1;
                q.push({v1[f.first][i],f.second+1});
            }
        }
    }
    cout<<-1;
    return;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int x,y;
        cin>>x>>y;
        v1[x].push_back(y);
        v2[y].push_back(x);
    }
    cin>>s>>t;
    dfs(t);
    for(int i=1;i<=n;i++)
    {
        vis2[i]=1;
        for(int j=0;j<v1[i].size();j++)//路径上的所有点的出边所指向的点都直接或间接与终点连通
        {
            if(!sign[v1[i][j]])
            {
                vis2[i]=0;
            }
        }
    }
    bfs();
    return 0;
}

4.送外卖

原题链接:https://ac.nowcoder.com/acm/contest/86654/F

和上一题有异曲同工之妙,但是这个要先建图建边再从后往前遍历打标,再次正向遍历,注意优先走a即可

查看代码
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=200010;
vector<int> v1[N],v2[N];
typedef pair <int ,int>PII;
int n,m,s,t;
bool f;
char ans[N];
int a[N],b[N];
int sign[N],vis[N],vis2[N];
void dfs(int x)//从后往前遍历打标
{
    sign[x]=1;
    for(int i=0;i<v1[x].size();i++)
    {
        if(!sign[v1[x][i]])
        {
            dfs(v1[x][i]);
        }
    }
}
void dfs2(int x,int step)
{
    if(x<0||x>=n)return;
    if(step>=n)return;//防死循环
    if(x==n-1)
    {
        f=true;
        return;
    }
    if(x+a[x]>=0&&x+a[x]<n&&sign[x+a[x]])
    {
        ans[step]='a';
        dfs2(x+a[x],step+1);
    }
    else
    {
        ans[step]='b';
        dfs2(x+b[x],step+1);
    }
}
int main()
{
    cin>>n;
    //所在小区i加上ai或bi是直接到达的地方
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        if(i+a[i]>=0&&i+a[i]<n)
            v1[i+a[i]].push_back(i);//建图建边
    }
    for(int i=0;i<n;i++)
    {
        cin>>b[i];
        if(i+b[i]>=0&&i+b[i]<n)
            v1[i+b[i]].push_back(i);
    }
    dfs(n-1);
    if(!sign[0])
    {
        cout<<"No solution!";
        return 0;
    }
    dfs2(0,0);
    if(f)
    {
        cout<<ans;
    }
    else
    {
        cout<<"Infinity!";
    }
    return 0;
}

5.数独挑战

原题链接:https://ac.nowcoder.com/acm/contest/86654/G

运用位运算,将每行每列每个区块变成二进制串,例如某一行有4,9这两个数,那么这一行的二进制串就是100001000,利用这个进行搜索,每次搜索锁定的某个空,遍历九个数字运用&运算判断行列块是否可以填这个数

查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[10][10];
int h[1000],l[1000],k[1000];
int ans,ok;
void dfs(int x,int y,int z) {
    if(ok)return;
    if(z>ans) 
    {
        ok=1;
            for(int i=1;i<=9;i++)
            {
            for(int j=1;j<=9;j++)
            {
                cout<<a[i][j]<<" ";
            }
            cout<<endl;
        }
        return; 
    }
    while (a[x][y])
    {
        y++;
        if (y > 9)x++, y = 1;
    }
    for (int i = 1; i <= 9; i++)
    {
        if(h[x]&(1<<i)||l[y]&(1<<i)||k[((x-1)/3)*3+(y+2)/3]&(1<<i))
        {
            continue;
        }
        a[x][y]=i;
        h[x]|=(1<<i),l[y]|=(1<<i),k[((x-1)/3)*3+(y+2)/3]|=(1<<i);
        dfs(x,y,z+1);
        a[x][y]=0;
        h[x]^=(1<<i),l[y]^=(1<<i),k[((x-1)/3)*3+(y+2)/3]^=(1<<i);
    }
}
signed main()
{
    for(int i=1;i<=9;i++)
    {
        for(int j=1;j<=9;j++)
        {
            cin>>a[i][j];
            if(a[i][j]==0)ans++;
            h[i]|=(1<<a[i][j]);
            l[j]|=(1<<a[i][j]);
            k[((i-1)/3)*3+(j+2)/3]|=(1<<a[i][j]);
        }
    }
    dfs(1,1,1);
    
    return 0;
}

6.单词接龙

原题链接:https://ac.nowcoder.com/acm/contest/86654/N

建图建边遍历即可

查看代码
#include<bits/stdc++.h>
using namespace std;
int a[100];
int ans;
int sign[1000000];
struct node{
    int x;//增长
    int num;//编号
    node(int x,int num):x(x),num(num){}
};
vector<vector<node>> g(30);
int n,ma;
string c="";
vector<string> s(1000000);
void dfs(int deep,int num)
{
    ma=max(ma,deep);
    for(int i=0;i<g[num].size();i++)
    {
        if(sign[g[num][i].num]<2) {
            sign[g[num][i].num]++;
            dfs(deep+g[num][i].x,g[num][i].num);
            sign[g[num][i].num]--;
        }
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
    }
    char p;
    cin>>p;
    for(int i=1;i<=n;i++)//建边,能连起来就搞一条边,并记录能多出来的长度
    {
        if(s[i][0]==p)g[0].push_back(node(s[i].size(),i));//开头是p的记录进去,从他们开始遍历
        for(int j=1;j<=n;j++)
        {
            int t=min(s[i].size(),s[j].size());
            for(int k=1;k<=t;k++)
            {
                if(s[i].substr(s[i].size()-k)==s[j].substr(0,k))
                {
                    g[i].push_back(node(s[j].size()-k,j));
                }
            }
        }
    }

    dfs(0,0);
    cout<<ma;
    return 0;
}

 

posted @ 2024-07-20 15:16  伊芙加登  阅读(15)  评论(0编辑  收藏  举报