zoukankan      html  css  js  c++  java
  • 搜索考试

    关于昨天搜索考试的题目考察内容大体如下:

    1.有重复元素的排列问题

    dfs + STL大法(去重)

    2.烈火金刚

    bfs板子题

    3.剪纸

    记忆化搜索

    4.玛丽有只小羔羊

    二分 + bfs

    难度排序

    1 < 2 < 3 < 4

    1.有重复元素的排列问题

    此题可以用STL模板自带的去重完成,其思想和全排列类似
    上代码

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    char a[505], b[505];//一个输入,一个存储
    int n, sum = 1;//先初始化1,因为字符串本身算一种
    
    void intn();//输入
    void dfs();//搜索
    
    int main() {
        intn();
        dfs();
        return 0;
    }
    
    void intn() {
    //  freopen("perm.in","r",stdin);这题目有毒啊 
    //  freopen("perm.put","w",stdout);
        scanf("%d", &n);
        scanf("%s", a);
        sort(a, a+n);
        strcpy(b, a);
    } 
    
    void dfs() {
        printf("%s
    ", a);
        while(next_permutation(a, a+n)) {//STL自动去重
            if(!strcmp(b, a)) continue;
            printf("%s
    ", a);
            sum ++;
        }
        printf("%d",sum);
    }

    2.烈火金刚

    bfs的板子题,但是要注意输入用字符,因为每个数字之间没有空格,%d会很自然的将一排数都读在一起,于是,输入就成功地出锅了...
    关于输入,如果要一个一个字符输的话,建议用cin,不能用scanf("%c"),否则就用字符串输入:scanf("%s"),但是也要注意用它会从0号位开始存.

    #include <cstdio>
    #include <iostream>
    #include <queue>
    using namespace std;
    
    const int MAXN = 1005;
    const int INF = 0x3f3f3f3f;//极值 
    
    int dx[8] = {0, 1, 0, -1};//方向数组x
    int dy[8] = {1, 0, -1, 0};//方向数组y
    
    struct note {
        int x, y;//坐标 
    };
    
    int n, m;
    char mp[MAXN][MAXN];//商城地图
    int ans[MAXN][MAXN];//答案数组
    int sx, sy;//初始坐标
    int gx, gy;//终点坐标
    
    int bfs();
    void intn();
    
    int main() {
        intn();
        printf("%d", bfs());
        return 0;
    } 
    
    void intn() {//初始化 + 输入
        scanf("%d", &n);//读入 边长
        m = n;
        for(int i = 1; i <= n; i ++) {//读入商场地图
            for(int j = 1; j <= m; j ++) {
                cin>>mp[i][j];
            }
        }
        scanf("%d %d %d %d", &sx, &sy, &gx, &gy);
        for(int i = 0; i <= n; i ++) {//答案数组初始化
            for(int j = 0; j <= m; j ++) {
                ans[i][j] = INF;
            }
        }
    }
    
    int bfs() {
        queue<note> q;
        ans[sx][sy] = 0;//初始化 
        note a, b;//定义 
        a.x = sx;
        a.y = sy;
        q.push(a);//起点入队
        while(q.size()) {
            a = q.front();//枚举当前地点
            q.pop();//弹出没用的地点
            if(a.x == gx && a.y == gy) {//到达目的地就跳出循环
                break;
            }
            for(int i = 0;i <= 3;i ++) {//枚举四种走法
                int nx = a.x + dx[i];//当前坐标
                int ny = a.y + dy[i];
                if(nx >= 0 && nx <= n && ny >=0 && ny <= m && mp[nx][ny] != '1' && ans[nx][ny] == INF) {//判断是否越界
                    b.x = nx;
                    b.y = ny;
                    q.push(b);//入队
                    ans[nx][ny] = ans[a.x][a.y] + 1;//更新答案步数
                }
            }
        }
        return ans[gx][gy];//返回
    }

    3.剪纸

    请注意 本题需要用 记忆化搜索 是有 明显提示的(注意我加粗的地方):

    【样例1解释】 对于样例1中的第一组操作(2 2 1)
    需要进行如下操作:
    1、将22的蜡光纸剪成21,代价是2^2=4
    2、将21的蜡光纸剪成11,代价是1^2=1
    最小代价为:2^2+1^2=5
    如果有小朋友想问样例第二组数据3怎么得到5的,由于必须剪断,所以得到面积1的代价+得到 面积2 的代价就是5,清楚了吧~
    【数据规模与说明】
    1≤t≤40910(这么多组,利用前面的结果求解果,可以利用前面的数据求结果)
    1≤n,m≤30,1≤p≤min(n*m,50)

    #include <cstdio>
    #include <iostream>
    using namespace std;
    
    int sum[35][35][55], ans;//sum[35][35][55]用作储存结果
    int p, m, n, t;
    
    int dfs(int n, int m, int p);
    void work();
    
    int main() {
        work();
        return 0;
    }
    
    void work() {
        scanf("%d", &t);
        while (t--) {
            scanf("%d %d %d", &m, &n, &p);
            if (m > n)//横着剪与竖着减结果一样
                swap(n, m);
            printf("%d
    ", dfs(m, n, p));
        }
    }
    
    int dfs(int n, int m, int p) {
        if (n * m == p || p == 0)//特判 1.当p的面积等于了n * m的面积 
            return 0;//或者 p的面积本身为零, 就不用剪
        if (sum[n][m][p]) //算过(记忆化的好处)
            return sum[n][m][p];
        int ans = 0x3f3f3f3f;//赋极值(对了,不能用INT_MAX, WJC已经用血的教训告诉我们,Ta很容易溢出)
        for (int i = 1; i <= n / 2; i++) {//剪一刀,少一半 横着剪
            for (int j = 0; j <= p; j++) {
                ans = min(ans, dfs(i, m, j) + dfs(n - i, m, p - j) + m * m);//更新
            }
        }
        for (int i = 1; i <= m / 2; i++) {//剪一刀,少一半 竖着剪
            for (int j = 0; j <= p; j++) {
                ans = min(ans, dfs(n, i, j) + dfs(n, m - i, p - j) + n * n);//更新
            }
        }
        return sum[n][m][p] = ans;返回
    }

    4.玛丽有只小羔羊

    这道题题面告诉我,是玛丽找羊,我就被骗了...
    正解应该是羊找玛丽

    why?

    because

    羊的位置是固定的,它只有一个点,而玛丽初始位置在第一层,并且第一层全是平台,可以随处走动,只要搜到了地面,就可以结束了,而玛丽需要枚举多个点,过程麻烦得多,于是我就 <font color=#9400D3 size=5 face = "微软雅黑">Runtime Error</font> <font color=white>然后,玛丽也迷路了...</font> 此题最重要的是要二分宽搜一起用,搜索的终点就是地面,搜到地面后,就结束搜索,考试时,没有想出来,gm讲解后我又打了一份;

    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <iostream>
    using namespace std;
    int n, m, x1, y1;
    bool a[55][55], falg[55][55];
    struct cjg {
    int r, c;
    } t1, t2, t3;
    queue<cjg> q;
    bool bfs(int x);
    int ef(int l, int r);
    int main() {
    char k;
    scanf("%d %d", &m, &n);
    for (int i = 1; i <= m; ++i) {
    scanf("%*c");//过滤字符
    for (int j = 1; j <= n; ++j) {
    cin >> k;
    if (k == '.')
    a[i][j] = 0;//0 -> 不能走
    else
    a[i][j] = 1;//1 -> 能走
    }
    }
    scanf("%d %d", &x1, &y1);//小羔羊的坐标
    if (x1 == m) {//特判 羊和玛丽在一层...
    printf("0
    ");
    return 0;
    }
    int ans = ef(1, m - x1);
    printf("%d
    ", ans);
    return 0;
    }
    int ef(int l, int r) {//二分
    while (l <= r) {
    int mid = (l + r) / 2;//枚举梯子长度
    if (bfs(mid) && !bfs(mid - 1))//梯子再短一丢丢就不行了
    return mid;//返回答案
    else if (bfs(mid))//梯子行,但是还有更好的答案
    r = mid;
    else
    l = mid + 1;//同上
    }
    }
    bool bfs(int x) {
    while (!q.empty()) q.pop();//清零
    memset(falg, 0, sizeof(falg));//清零
    falg[x1][y1] = 1;//入队
    t1.r = x1;
    t1.c = y1;
    q.push(t1);//入队
    while (!q.empty()) {//不为空就继续搜
    t2 = q.front();
    q.pop();
    t3 = t2;
    t3.c = t2.c + 1;//向右走
    if (a[t3.r][t3.c] && !falg[t3.r][t3.c]) {//判断边界
    falg[t3.r][t3.c] = 1;//标记
    q.push(t3);//入队
    }
    t3 = t2;//重新赋值
    t3.c = t2.c - 1;//向左走
    if (a[t3.r][t3.c] && !falg[t3.r][t3.c]) {//判断边界
    falg[t3.r][t3.c] = 1;//标记
    q.push(t3);//入队
    }
    for (int i = 1; i <= x; i++) {//往上走 
    if (!falg[t2.r - i][t2.c] && a[t2.r - i][t2.c]) {
    t3 = t2;
    t3.r = t2.r - i;
    falg[t3.r][t3.c] = 1;//标记
    q.push(t3);//入队
    break;
    }
    }
    for (int i = 1; i <= x; i++) {//往下走
            if (!falg[t2.r + i][t2.c] && a[t2.r + i][t2.c]) {
                t3 = t2;
                t3.r = t2.r + i;
                if (t3.r == m)
                    return 1;
                falg[t3.r][t3.c] = 1;//标记
                q.push(t3);//入队
                break;
            }
        }
    }
    return 0;//四个方向都不行,返回0

    }

    # 完
    ps:附上[成绩单](http://222.180.160.110:1024/contest/465/ranklist)
       <font color=white>ps:为什么初一的比赛都不会造成积分变化呢?</font>
  • 相关阅读:
    踩踩踩
    c语言可变参
    C++开发者都应该使用的10个C++11特性
    c++11 条件变量 生产者-消费者 并发线程
    c++11 线程
    C++ 虚函数表解析 继承
    坐标系
    C++ 容器:顺序性容器、关联式容器和容器适配器
    全面深入介绍C++字符串:string类
    做一个懒COCOS2D-X程序猿(一)停止手打所有cpp文件到android.mk
  • 原文地址:https://www.cnblogs.com/cqbz-ChenJiage/p/13504677.html
Copyright © 2011-2022 走看看