搜索整理

搜索分为两种 深度优先搜索 和 广度优先搜索 个人认为解决搜索问题的关键是 找到状态的转移 并且在有限的时间或者空间内找到正确的答案

1.深度优先搜索
dfs是以深度优先的方式 遍历二叉树 一条路走到黑 说白了就是瞎几把递归 一般数据量较小的时候 可以采用这种方法 最基础的问题就是全排列的生成

#include <bits/stdc++.h>

using namespace std;

int a[25];
bool vis[25];
int n;

void dfs(int num)
{
    if(num == n)
    {
        for(int i=0;i<n;i++)
            cout << a[i] << ' ';
        cout << '\n';

        return ;
    }

    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            vis[i] = 1;
            a[num] = i;

            dfs(num+1);

            vis[i] = 0;
        }
    }
}

int main()
{
    cin >> n;

    dfs(0);
}

其中 dfs常见的格式为

         if(!vis[i])
        {
            vis[i] = 1;

            dfs(num+1);

            vis[i] = 0;
        }    

也就是走到尽头回溯的过程中 将原来的状态还原

FJUT 2574
某个外国探险队在非洲沙漠中发现了二战时期希特勒埋藏的n个地下宝库(编号为1…n),并且还记下了从一个宝库走到另一个宝库的时间(有的宝库之间无通路,无通过时间)。几经知道每个宝库中藏有一定数量的宝藏,但由于德国法西斯在建造宝库时设有保护措施,因而每个宝库只能进入通过一次。在第一个宝库内可以取得打开其它宝库的钥匙(第一个宝库可以不用钥匙就进入)。另外,探险队还发现,在进入第一个宝库的同时将触发一个爆破装置,因而所有的宝库将在tk秒后同时爆炸。

请你设计一种最佳的从1开始的取宝藏的方案,使在宝库爆炸前(包括爆炸时)能取得最多的宝藏。
例:有4个宝库:1、2、3、4

其中宝藏数量为:100,60,80,70
通过时间(没有给出通过时间的表示无通路):

1—2 20秒

1—3 30秒

2—4 20秒

3—4 15秒

爆炸时间:50秒

此时方法有:
1—2—4

计40秒,可取100+60+70=230

或:
1—3—4

计45秒,可取100+80+70=250

则最佳方案为:

1—3—4

可取宝藏250

Input
包含多个测试数据,每个测试数据的第一行有三个用空格隔开的整数n(1≤n≤20), k(1≤k≤50), tk(1≤tk≤1000)。

其中n表示宝库的数目,k表示由k个通路,tk表示爆炸的时间。

接下来k行,每行有三个数据(x, y, t),表示从x→y或y→x所需时间t(即无向图)。

最后一行有n个整数,表示宝库中的宝藏数。

一行单独的一个0表示输入结束
Output
每行一个数,表示能取到的最多的宝藏数。

SampleInput
4 4 50
1 2 20
1 3 30
2 4 20
3 4 15
100 60 80 70
0
SampleOutput
250

#include <bits/stdc++.h>

using namespace std;

const int N = 25;

int mp[N][N];
bool vis[N];
int a[N];

int n,k,tk;
int res;


void dfs(int x,int time,int val)///x代表当前点 time为时间 val为宝藏数
{
    res = max(res,val);

    for(int i=1; i<=n; i++)
    {
        if(!vis[i] && (mp[x][i] || mp[i][x]))
        {
            if(time+mp[x][i] <= tk)
            {
                vis[i] = 1;
                dfs(i,time+mp[x][i],val+a[i]);
                vis[i] = 0;
            }
        }
    }
}

int main()
{
    while(~scanf("%d",&n)  && n)
    {
        scanf("%d%d",&k,&tk);

        res = 0;
        memset(vis,0,sizeof(vis));
        memset(mp,0x3f,sizeof(mp));///最为关键的初始化  没写直接T

        while(k -- )
        {
            int x,y,t;

            scanf("%d%d%d",&x,&y,&t);

            mp[x][y] = mp[y][x] = t;
        }

        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);

        vis[1] = 1;
        dfs(1,0,a[1]);

        printf("%d\n",res);

    }
    return 0;
}

HDU 1181

#include <bits/stdc++.h>

using namespace std;

const int N = 1005;
string s,t;
bool vis[N];

bool flag;
int n;

void init()
{
   s = t = "";
   flag = false;
   memset(vis,0,sizeof(vis));
}

void dfs(char temp)
{
    int i;

    if(temp == 'm')
    {
        flag = true;
        return ;
    }

    for(int i=0;i<n;i++)
    {
        if(s[i] == temp && !vis[i])
        {
            vis[i] = 1;
            /// temp  = t[i]; dfs(temp);  如果改成这句则会出现错误
            dfs(t[i]);

            vis[i] = 0;
        }
    }
}

int main()
{
    string str;

    while(cin >> str)
    {
        init();
        n = 0;

        while(str[0] != '0')
        {
            s += str[0];
            t += str[str.size()-1];

            cin >> str;
            n ++ ;
        }

        dfs('b');

        if(flag)
            cout << "Yes.";
        else
            cout << "No.";

        cout << '\n';
    }

    return 0;
}

POJ 1562
dfs 求联通块个数

#include <iostream>
#include <cstring>

using namespace std;

const int N = 105;
char mp[N][N];

int n,m;
int res;

int dx[] = {1,-1,0,0,-1,-1,1,1};
int dy[] = {0,0,-1,1,1,-1,1,-1};

void dfs(int x,int y)
{
    mp[x][y] = '*';

    for(int i=0;i<8;i++)
    {
        int xx = x + dx[i];
        int yy = y + dy[i];

        if(xx >=0 && xx < n && yy >=0 && yy < m && mp[xx][yy] == '@')
            dfs(xx,yy);
    }
}

int main()
{
    ios::sync_with_stdio(false);

    while(cin >> n >> m && n && m)
    {
        int res = 0;

        for(int i=0; i<n; i++)
            cin >> mp[i];
        /// key
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(mp[i][j] == '@')
                {
                    res ++;
                    dfs(i,j);
                }
            }
        }

        cout << res << '\n';
    }

    return 0;
}

FJUT 2915

注意标记部分 不能只是单纯的标记为1 如果一个点被覆盖了两次 而你回溯一次的时候就把他标记成可使用状态 就会出错

#include <bits/stdc++.h>

using namespace std;

const int N = 15;
int a[N][N];
int vis[N][N];

int res,n,m;
int dx[] = {0,1,-1,0,0,-1,-1,1,1};
int dy[] = {0,0,0,-1,1,1,-1,1,-1};


void dfs(int x,int y,int v)
{
    if(y > m)
    {
        x ++ ;
        y = 1 ;
    }

    if(x > n)
    {
        res = max(res,v);
        return ;
    }

    if(!vis[x][y])
    {
        for(int i=0;i<9;i++)
            vis[x+dx[i]][y+dy[i]] ++ ;

        dfs(x,y+2,v+a[x][y]);

        for(int i=0;i<9;i++)
            vis[x+dx[i]][y+dy[i]] -- ;
    }

    dfs(x,y+1,v);
}
int main()
{
    int t;

    scanf("%d",&t);

    while(t--)
    {
        memset(vis,0,sizeof(vis));

        scanf("%d%d",&n,&m);

        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
               scanf("%d",&a[i][j]);

        res = 0;
        dfs(1,1,0);

        printf("%d\n",res);

    }
    return 0;
}

2.广度优先搜索
将可以从当前状态转换到下个状态全部情况存入队列中 再将当前转态抛弃 如此循环反复 直到找到正确答案 使用的空间会较大 且 一般得到的答案最短或者最优秀的

迷宫问题 记录路径的方法

#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
char maps[10][10],vis[10][10],moves[4][2]={-1,0,1,0,0,1,0,-1};
struct node
{
    int x,y;
};
node p,q,r,temp;
void bfs()
{
    node pre[10][10],way[105];
    queue<node>que;
    que.push(p);
    int top;
    while(!que.empty())
    {
        r=que.front();
        que.pop();
        if(r.x==q.x&&r.y==q.y)
        {
            top=0;
            while(1)
            {
                way[top++]=r;
                if(r.x==p.x&&r.y==p.y)
                    break;
                r=pre[r.x][r.y];
            }
            while(top--)
            {
                printf("(%d, %d)\n",way[top].x-1,way[top].y-1);
            }
        }
        for(int i=0;i<4;i++)
        {
            temp.x=r.x+moves[i][0];
            temp.y=r.y+moves[i][1];
            if(!maps[temp.x][temp.y]&&!vis[temp.x][temp.y])
            {
                pre[temp.x][temp.y]=r;
                vis[temp.x][temp.y]=1;
                que.push(temp);
            }
        }
    }
}
main()
{
    p.x=p.y=1;
    q.x=q.y=5;
    memset(maps,1,sizeof(maps));
    for(int i=1;i<=5;i++)
        for(int j=1;j<=5;j++)
           scanf("%d",&maps[i][j]);
    bfs();
}

3.搜索优化
1.dfs剪枝 当确定当前状态已经无解时 直接返回 减少递归层数 缩短时间
HDU 1518

https://blog.csdn.net/weixin_44144278/article/details/102698238

2.bfs中如果已经出现过的状态 采用标记数组的方式 不将其如队列减少内存
HDU 1195

#include <bits/stdc++.h>

using namespace std;

string str;

struct node
{
    string s;
    int sum;
};

queue<node>que;
bool vis[10005];

bool check(string s)
{
    int sum = (s[0]-'0')*1000 + (s[1]-'0')*100 + (s[2]-'0')*10 + s[3]-'0';
    ///如果已经出现的状态不会再入队列
    if(vis[sum])
        return 0;
    vis[sum] = 1;
    return 1;
}

void bfs()
{
    node now;

    while(!que.empty())
    {
        now = que.front();
        que.pop();

        if(now.s == str)
        {
            printf("%d\n",now.sum);
            return ;
        }

        for(int i=0; i<4; i++)
        {
            node a,b;
            string t = now.s;

            if(t[i]!='9')
                t[i] += 1;
            else
                t[i] = '1';

            if(check(t))
            {
                a.s = t;
                a.sum = now.sum +1;
                que.push(a);
            }

            t = now.s;

            if(t[i]!='1')
                t[i] -= 1;
            else
                t[i] = '9';

            if(check(t))
            {
                b.s = t;
                b.sum = now.sum +1;
                que.push(b);
            }

            if(i == 0)
            {
                t = now.s;
                swap(t[i],t[i+1]);

                if(check(t))
                {
                    a.s = t;
                    a.sum = now.sum +1;
                    que.push(a);
                }
            }
            else if(i > 0 && i < 3)
            {
                t = now.s;
                swap(t[i],t[i+1]);

                if(check(t))
                {
                    a.s = t;
                    a.sum = now.sum +1;
                    que.push(a);
                }

                t = now.s;
                swap(t[i],t[i-1]);

                if(check(t))
                {
                    a.s = t;
                    a.sum = now.sum +1;
                    que.push(a);
                }
            }
            else if(i == 3)
            {
                t = now.s;
                swap(t[i],t[i-1]);

                if(check(t))
                {
                    a.s = t;
                    a.sum = now.sum +1;
                    que.push(a);
                }
            }
        }
    }
}
int main()
{
    int t;
    ios::sync_with_stdio(false);

    while(cin >> t)
    {
        while(t--)
        {
            memset(vis,0,sizeof(vis));
            while(!que.empty())
                que.pop();

            string s;
            cin >> s >> str;

            node now;

            now.s = s;
            now.sum = 0;

            que.push(now);

            bfs();
        }
    }
    return 0;
}

3.bfs打表 + cantor展开

#include <bits/stdc++.h>

using namespace std;

const int N = 15;
const int M = 100005;

char st[N],ed[N];
char change[N];

bool vis[M];
string res[M];

int fac[] = {1,1,2,6,24,120,720,5040,40320};
int mov[3][8] = {{7,6,5,4,3,2,1,0},{3,0,1,2,5,6,7,4},{0,6,1,3,4,2,5,7}};

struct node
{
    char s[9];
};

int gethash(char *s)
{
    int sum = 0;
    int cnt ;

    for(int i=0; i<8; i++)
    {
        cnt = 0;

        for(int j=i+1; j<8; j++)
        {
            if(s[j] < s[i])
                cnt ++ ;
        }
        sum += cnt*fac[8-i-1];
    }

    return sum;
}

void bfs()
{
    queue<node>que;

    node now;

    for(int i=0; i<8; i++)
        now.s[i] = i+'1';

    int pos = gethash(now.s);

    que.push(now);

    vis[pos] = 1;

    while(!que.empty())
    {
        now = que.front();
        que.pop();

        int posx = gethash(now.s);

        node next;

        for(int i=0; i<3; i++)
        {
            for(int j=0; j<8; j++)
                next.s[j] = now.s[mov[i][j]];

            int pos = gethash(next.s);
            if(vis[pos])
                continue;

            vis[pos] = 1;

            res[pos] = res[posx]+(char)('A'+i);

            que.push(next);
        }
    }
}

int main()
{
    bfs();

    while(~scanf("%s%s",st,ed))
    {
        for(int i=0; i<8; i++)
            change[st[i]-'1'] = i+'1';

        for(int i=0; i<8; i++)
            ed[i] = change[ed[i]-'1'];

        int pos = gethash(ed);

        cout << res[pos] << '\n';
    }

    return 0;
}
发布了54 篇原创文章 · 获赞 0 · 访问量 1208

猜你喜欢

转载自blog.csdn.net/weixin_44144278/article/details/104070511