HZNUACM寒假集训Day3小结 搜索

      简单搜索

1.DFS

 UVA 548 树

 1.可以用数组方式实现二叉树,在申请结点时仍用“动态化静态”的思想,写newnode函数 

 2.给定二叉树的中序遍历和后序遍历,可以构造出这棵二叉树,方法是根据后序遍历找到根,然后在中序遍历中找到树根,从而找出左右子树的结点列表然后递归 构造左右子树

 3.注意这里输入的模板,用stringstream会方便

#include<iostream>
#include<string>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<queue>
#include<stack>
#include<sstream>
#include<cstdio>
#define INF 0x3f3f3f3f
const int maxn = 1e6 + 5;
const double PI = acos(-1.0);
typedef long long ll;
using namespace std;

const int maxv = 10000 + 10;
int in_order[maxv], post_order[maxv], lch[maxv], rch[maxv];
int n;

bool read_list(int* a) {
    string line;
    if (!getline(cin, line)) return false;
    stringstream ss(line);
    n = 0;
    int x;
    while (ss >> x) a[n++] = x;
    return n > 0;
}

int build(int L1, int R1, int L2, int R2) {
    if (L1 > R1) return 0;
    int root = post_order[R2];
    int p = L1;
    while (in_order[p] != root) p++;
    int cnt = p - L1;
    lch[root] = build(L1, p - 1, L2, L2 + cnt - 1);
    rch[root] = build(p + 1, R1, L2 + cnt, R2 - 1);
    return root;
 }

int best, best_sum;

void dfs(int u, int sum) {
    sum += u;
    if (!lch[u] && !rch[u]) {
        if (sum < best_sum || (sum == best_sum && u < best)) {
            best = u;
            best_sum = sum;
        }
    }
    if (lch[u]) dfs(lch[u], sum);
    if (rch[u]) dfs(rch[u], sum);
}

int main() {
    while (read_list(in_order)) {
        read_list(post_order);
        build(0, n - 1, 0, n - 1);
        best_sum = 10000000;
        dfs(post_order[n - 1], 0);
        cout << best << "\n";
    }
    return 0;
}

    2000提高组-C  单词接龙  

    用substr判断能否接上

#include<iostream>
#include<string>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<queue>
#include<stack>
#include<sstream>
#include<cstdio>
#define INF 0x3f3f3f3f
const int maxn = 1e6 + 5;
const double PI = acos(-1.0);
typedef long long ll;
using namespace std;

string s[25];
int vis[25];
int Max=-1;
int n;

void dfs(string x, int len) {
    Max = max(Max, len);
    for (int i = 1; i <= n; i++) {
        if (vis[i] == 2) continue;
        int l1 = x.length();
        int l2 = s[i].length();
        int p = 1;
        while (p < min(l1, l2))
            if (x.substr(l1 - p) == s[i].substr(0, p)) break; else p++;
        if (p < min(l1, l2)) {
            vis[i]++;
            dfs(x.substr(0,l1-p)+s[i], len + s[i].length()-p);
            vis[i]--;
        }
    }
}

int main() {
    std::ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;
    for (int i = 1; i <= n; i++) cin >> s[i];
    cin >> s[0];
    s[0] = "0" + s[0];
    dfs(s[0], s[0].length());
    cout << Max-1;
    return 0;
}

    回溯    N皇后问题 http://acm.hdu.edu.cn/showproblem.php?pid=2553

   

#include<iostream>
#include<string>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<queue>
#include<stack>
#include<sstream>
#include<cstdio>
#define INF 0x3f3f3f3f
const int maxn = 1e6 + 5;
const double PI = acos(-1.0);
typedef long long ll;
using namespace std;

int x[15], y[15];   //x[i]为第i行所在的列
int n1, ans;

bool place(int k) {
    for (int i = 1; i < k; i++) {
        if (abs(x[i] - x[k]) == abs(i - k) || x[i] == x[k]) return false;
    }
    return true;
}  //判断位置是否可行
void dfs(int a) {   //遍历到a行,共n1行
    if (a > n1) ans++;    //已经放了n1个皇后
    else {
        for (int i = 1; i <= n1; i++) {
            x[a] = i;
            if (place(a)) dfs(a + 1);
        }
    }
}

int main() {
    int n;
    for (int i = 1; i <= 10; i++) {
        ans = 0;
        n1 = i;
        dfs(1);
        y[i] = ans;
    }
    while (scanf("%d", &n), n) {
        printf("%d\n", y[n]);
    }
    return 0;
}

    BFS

    BFS通常用队列实现,开一个vis数组标记是否访问过

 

      如Catch That Cow http://poj.org/problem?id=3278   如果用DFS会TLE,考虑DFS

      

#include<iostream>
#include<string>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<queue>
#include<stack>
#include<sstream>
#include<cstdio>
#define INF 0x3f3f3f3f
const int maxn = 1e6 + 5;
const double PI = acos(-1.0);
const int N = 200100;
typedef long long ll;
using namespace std;

int n, k;
struct Node {
    int x;
    int step;
};
queue<Node> q;
int vis[N];

void bfs() {
    int X, Step;
    while (!q.empty()) {
        Node Q = q.front();
        q.pop();
        X = Q.x;
        Step = Q.step;
        if (X == k) {
            printf("%d", Step);
            return;
        }
        if (X >= 1 && (!vis[X - 1])) {
            Node p;
            vis[X - 1] = true;
            p.x = X - 1;
            p.step = Step + 1;
            q.push(p);
        }
        if (X <= k && (!vis[X + 1])) {
            Node p;
            vis[X + 1] = true;
            p.x = X + 1;
            p.step = Step + 1;
            q.push(p);
        }
        if (X <= k && (!vis[X * 2])) {
            Node p;
            vis[X * 2] = true;
            p.x = X * 2;
            p.step = Step + 1;
            q.push(p);
        }
    }
}

int main() {
    scanf("%d%d", &n, &k);
    Node NODE ;
    NODE.x = n;
    NODE.step = 0;
    q.push(NODE);
    bfs();
    return 0;
}

    回溯法一般是要找到一个(或者所有)满足约束的解(或者某种意义下的最优解),而状态空间搜索一般是要找到一个从初始状态到终止状态的路径  

    路径寻找问题可以归结为隐式图的遍历,它的任务是找到一条从初始状态到终止状态的最优路径,而不像回溯法那样找到一个符合某些条件的解。

   八数码问题

#include<iostream>
#include<map>
#include<queue>

using namespace std;

queue<int>Q;
map<int,int>vis;//标记数组
map<int,int>step;//记录到这种状态的步数

int dir[4][2]={-1,0,0,1,1,0,0,-1};//上,右,下,左
int mat[3][3];
int state;//输入的初始状态
int r,c;

void input()//输入数据并将矩阵转化为一个九位整数
{
    int tmp=0;
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
        {
            cin>>mat[i][j];
            tmp=tmp*10+mat[i][j];
        }
    state=tmp;
}

bool can_move(int u,int d)//判断是否可以走
{
    for(int i=2;i>=0;i--)//将整数变回矩阵才好判断
    {
        for(int j=2;j>=0;j--)
        {
            mat[i][j]=u%10;
            u/=10;
            if(mat[i][j]==0)
            {
                r=i;
                c=j;
            }
        }
    }
    //判断四个方向是否能走
    if((d==0&&r==0)||(d==1&&c==2)||(d==2&&r==2)||(d==3&&c==0))
        return 0;
    return 1;
}

int move_to(int u,int d)//返回从状态u走到的状态
{
    int tmp=0;
    int nr=r+dir[d][0];
    int nc=c+dir[d][1];
    mat[r][c]=mat[nr][nc];
    mat[nr][nc]=0;
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
            tmp=tmp*10+mat[i][j];
    }
    return tmp;
}

int bfs(int s)
{
    Q.push(s);
    vis[s]=1;
    step[s]=0;
    while(Q.size())
    {
        int u,v;
        u=Q.front();
        Q.pop();
        if(u==123456780)
            return step[u];
        for(int i=0;i<4;i++)
        {
            if(can_move(u,i))
            {
                v=move_to(u,i);
                if(!vis[v])
                {
                    vis[v]=1;
                    step[v]=step[u]+1;
                    Q.push(v);
                }
            }
        }
    }
    return -1;
}

int main()
{
    input();
    int ans=bfs(state);
    cout<<ans<<endl;
    return 0;
}



     拓扑排序 

     不包含有向环的有向图称为有向无环图(DAG),如果图中存在有向环,则不存在拓扑排序

原文地址:https://www.cnblogs.com/hznumqf/p/12243776.html