zoukankan      html  css  js  c++  java
  • 蓝桥杯 算法提高 3000米排名预测 DFS 递归搜索 next_permutation()使用

    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <cstdlib>
    #include <cstdio>
    using namespace std;
    
    const int maxn = 20 + 2;
    const int maxP = 20000 + 20;
    struct Predict {
        int nPre;         //n个预测
        int rSort[maxn];  //n个人编号相对排序
        int isOk;         //正确否 
    } pre[maxn];          //围观人的预测
     
    int n, m;               //运动员n,围观人m 
    int ans;                //预测的可能数 
    int predict[maxP][maxn];//正确的排名 
    int pre_o[maxn];        //一次正确的排名 
    bool used[maxn];        //标志数组 
    void input();           //输入 
    bool check(); 
    void DFS(int n); 
    void solve();
    
    //输入 
    void input()
    {
        memset(used, 0, sizeof(used));
        scanf("%d%d", &n, &m);
        for (int i = 0; i < m; i++) {
            scanf("%d", &pre[i].nPre);
            for (int j = 0; j < pre[i].nPre; j++) {
                scanf("%d", &pre[i].rSort[j]);
            }
            scanf("%d", &pre[i].isOk);
        }
    }
    
    bool check()
    {
        bool flag_1 = true,
             flag_2 = true;
        for (int i = 0; i < m; i++)
        {
            //预测正确 且 标志是正确标志 
            if (pre[i].isOk && flag_1)
            {
                int j = 0;  //代表预测数的索引 
                //k--运动员总数 
                for (int k = 0; j < pre[i].nPre && k < n; k++)  //k代表第几个选手
                {
                    //预测位置 ==  运动员正确位置 
                    if (pre[i].rSort[j] == pre_o[k]) {
                        j++;
                    }
                } 
                if (j < pre[i].nPre) {   //有位置不等于正确排序 (pre_o和正确的预测不一致,则false) 
                    flag_1 = false;
                }
            }
            else 
            {
                int j = 0;
                for (int k = 0; j < pre[i].nPre && k < n; k++) 
                {
                    if (pre[i].rSort[j] == pre_o[k]) {
                        j++;
                    }
                }
                if (j == pre[i].nPre) { //pre_o和不正确的预测一致,所以也应该是false 
                    flag_2 = false;
                }
            }
            if (!flag_1 || !flag_2) break;   //有一个错误即错误 
        }
        if (flag_1 && flag_2) return true;
        else return false;
    }
    
    //超时??? 
    void DFS(int cur)
    {
        if (cur == n && check())  //结束条件
        {
            for (int i = 0; i < n; i++) {    //用dfs,亦是  所有排名按字典序依次输出。
                predict[ans][i] = pre_o[i];  //每种可能下的,排名 
            }    
            ans++;                //方案数++ 
        } 
        //当前人小于参赛总数 
        if (cur < n)
        {
            for (int i = 0; i < n; i++) 
            {
                if (!used[i])    //判断当前人是否排序过
                {
                    pre_o[cur] = i;    //设置当前预测 
                    used[i] = true;    //当前人标志为访问过 
                    DFS(cur + 1);      //下一个人
                    used[i] = false;   //重新标志为false 
                } 
            }
        }
    }
    
    void DFS_2(int n)   //用STL的话,全排列这段代码就够了
    {
        for (int i = 0; i < n; i++) pre_o[i] = i;
        do {
            if (check()) {
                for (int i = 0; i < n; i++) {
                    predict[ans][i] = pre_o[i];
                }
                ans++;
            }
        } while (next_permutation(pre_o, pre_o + n));
    } 
    
    //处理函数 
    void solve()
    {
        input();
    //    DFS(0);
        DFS_2(n);
        printf("%d
    ", ans);
        for (int i = 0; i < ans; i++)
        {
            printf("%d", predict[i][0]);
            for (int j = 1; j < n; j++) {   //n个运动员的排名 
                printf(" %d", predict[i][j]);
            }
            printf("
    ");
        }
    }
    
    int main()
    {
        solve();
        return 0;    
    }

    //一开始使用了自己写的全排列,然后对排列进行check判断,超时了.....

    //然后使用了 STL里的 next_permutation(a, a + n) 然后才过

    套路总结:

    1. 第一步还是先写下面模板

    const int maxn = 20 + 2;
    const int maxP = 20000 + 20;
    struct Predict {
        int nPre;         //n个预测
        int rSort[maxn];  //n个人编号相对排序
        int isOk;         //正确否 
    } pre[maxn];          //围观人的预测
     
    int n, m;               //运动员n,围观人m 
    int ans;                //预测的可能数 
    int predict[maxP][maxn];//正确的排名 
    int pre_o[maxn];        //一次正确的排名 
    bool used[maxn];        //标志数组 
    void input();           //输入 
    bool check();           //发现check()是DFS水题里面最重要的一步了!!几乎这个能想出来,整个题目就差不多了
    void DFS(int n);        //自己写的全排列....超时了......
    void DFS_2(int n); //next_permutation()
    void solve();

    //下对check进行分析

    //主要就是全排列0~n-1的可能,然后用预测的结果与其比较

    //预测正确, 则看是否全排列等于该预测结果,不 一致,则该排列不正确, return false

    //预测错误, 则看是否全排列等于该预测结果, 一致,   则该排列不正确, return false

    //check()返回true, 则应该将预测结果添加到总的predict[ans][i]中, (结果数)ans++; 

    bool check()
    {
        bool flag_1 = true,
             flag_2 = true;
        for (int i = 0; i < m; i++)
        {
            //预测正确 且 标志是正确标志 
            if (pre[i].isOk && flag_1)
            {
                int j = 0;  //代表预测数的索引 
                //k--运动员总数 
                for (int k = 0; j < pre[i].nPre && k < n; k++)  //k代表第几个选手
                {
                    //预测位置 ==  运动员正确位置 
                    if (pre[i].rSort[j] == pre_o[k]) {
                        j++;
                    }
                } 
                if (j < pre[i].nPre) {   //有位置不等于正确排序 (pre_o和正确的预测不一致,则false) 
                    flag_1 = false;
                }
            }
            else 
            {
                int j = 0;
                for (int k = 0; j < pre[i].nPre && k < n; k++) 
                {
                    if (pre[i].rSort[j] == pre_o[k]) {
                        j++;
                    }
                }
                if (j == pre[i].nPre) { //pre_o和不正确的预测一致,所以也应该是false 
                    flag_2 = false;
                }
            }
            if (!flag_1 || !flag_2) break;   //有一个错误即错误 
        }
        if (flag_1 && flag_2) return true;
        else return false;
    }
  • 相关阅读:
    SpringBoot前端模板
    Http协议与TCP协议简单理解
    Kafka简介、基本原理、执行流程与使用场景
    初学Kafka工作原理流程介绍
    Redis数据持久化、数据备份、数据的故障恢复
    zookeeper的分布式锁
    eclipse下将maven项目打包为jar(1.不带第三方jar,2.带第三方jar)
    Redis入门篇(安装与启动)
    java操作Redis缓存设置过期时间
    java单例模式实现
  • 原文地址:https://www.cnblogs.com/douzujun/p/6654283.html
Copyright © 2011-2022 走看看