2018蓝桥杯模拟赛(一)C【模拟】D【dp】E【全排列】F【dfs】

C.U型数字
最近蒜头君喜欢上了U型数字,所谓U型数字,就是这个数字的每一位先严格单调递减,后严格单调递增。比如 212212212 就是一个U型数字,但是 333333333, 989898, 567567567, 313133131331313,就是不是U型数字。

现在蒜头君问你,[1,100000][1,100000][1,100000] 有多少U型数字?

提示:请不要输出多余的符号。

#include<iostream>
#include<cstring>
using namespace std;
int num[10];
int cnt = 0;
int main()
{
    int weishu = 0;
    int j;
    int flag;
    for(int i = 100;i<=99999;i++)
    {

        memset(num,0,sizeof(num));
        int temp = i;
        for(j = 0;temp != 0;j++)
        {
            num[j] = temp%10;
            temp = temp/10;
        }
        weishu = j;
        j= 1;
        while(num[j]<num[j-1])
        {
            j++;
        }
        flag = j;
        while(num[j]>num[j-1])
        {
            j++;
        }
        //保证两个循环都进去过才能说明存在严格递减和严格递增
        if(j == weishu&&j>flag&&flag!=1) //flag!=1保证进入第一个循环 j>flag 保证进入第二个循环 
        {
            cnt++;
        //  cout<<i<<' ';
        }
    }
    cout<<cnt<<endl;
}


D LIS
LIS是最长上升子序列。什么是最长上升子序列? 就是给你一个序列,请你在其中求出一段最长严格上升的部分,它不一定要连续。

就像这样:222, 333, 444, 777 和 222, 333, 444, 666 就是序列 222 555 333 444 111 777 666 的两个上升子序列,最长的长度是 444。

#include<iostream>
#include<cstring>
using namespace std;

int f[10000], b[10000];
int lis(int n) {
    memset(f, 0, sizeof f);
    int res = 0;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < i; ++j) {
            if (b[j] < b[i]) {
                f[i] = max(f[i],f[j]+1); //填空  dp: 每再前面遇到一个小于自己的数,就判断如果加上这个数那么f[i] = f[j]+1,还是不加上这个数保持f[i],选择大的
            }
        }
        res = max(res, f[i]);
    }
    return res+1;
}
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) {
        scanf("%d", b + i);
    }
    printf("%d\n", lis(n));
    return 0;
}

E 全排列
相信大家都知道什么是全排列,但是今天的全排列比你想象中的难一点。我们要找的是全排列中,排列结果互不相同的个数。比如:aab 的全排列就只有三种,那就是aab,baa,aba。

代码框中的代码是一种实现,请分析并填写缺失的代码。

思路:填空的地方的意思是,如果i的后面有和s[i] 相等且访问过的字符,则不可以(break),一旦break,j 就不能等于len,就不能继续递归。那么怎么理解这个呢?
先想一下简化的问题吧,假如输入的字符串不重复,例如abcd,那么就是简单的dfs了,一个for循环加一个vis判断,如果判断可以,继续递归。

当有重复的字符时候就比较麻烦了,比如aab,单纯的用递归会输出重复的。那么怎么加上限定条件呢。

这里,我们让重复的这些字符只顺序输出一遍,这样就不会重复

这是什么意思呢,比如说aabc,我们只允许第一个a访问后再访问第二个a,不允许访问第二个,再第一个。

再如,abacda,那三个a只能按顺序访问。

原理是什么呢,用了点高中学的排列组合的知识,先排重复的,例如我们搞abacda这个例子, 先排三个a, 就是 aaa,那么剩下的就相当于直接插入到aaa中,那么如果我们aaa如果按多种顺序排,就会产生多种结果,所以只能按顺序访问。

那么又如何用算法实现呢,直接加个if判断就行了,判断i之后的有没有访问过的且相等的。例如,aabc这个例子,我们第一轮选完之后,到了第二个a,然后进入递归,for循环又从0开始,到了第一个a,然后从这个之后去判断有没有访问过的a,结果判断有,违反了顺序,所以结束。

这个题目的关键也就是排除重复的

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e3;
char str[N], buf[N];//buffer
int vis[N], total, len;
void arrange(int num) {
    if (num == len){
        printf("%s\n", buf);
        total++;
        return;
    }
    for (int i = 0; i < len; ++i) {
        if (!vis[i]) {
            int j;
            for (j = i + 1; j < len; ++j) {
            //比如递归到buf[1] = 
                if (str[i]==str[j]&&vis[j])//填空
                 {
                    break;
                }
            }
            if (j == len) {
                vis[i] = 1;
                buf[num] = str[i];
                arrange(num + 1);
                vis[i] = 0;
            }
        }
    }
}
int main() {
    while (~scanf("%s",str)) {
        len = strlen(str);
        sort(str, str + len);
        total = 0;
        buf[len] = '\0';
        arrange(0);
        printf("Total %d\n", total);
    }
    return 0;
}

蒜头君今天突然开始还念童年了,想回忆回忆童年。他记得自己小时候,有一个很火的游戏叫做数独。便开始来了一局紧张而又刺激的高阶数独。蒜头君做完发现没有正解,不知道对不对? 不知道聪明的你能否给出一个标准答案?

标准数独是由一个给与了提示数字的 9×9网格组成,我们只需将其空格填上数字,使得每一行,每一列以及每一个 3×3 宫都没有重复的数字出现。
这里写图片描述
输出这个数独得正解,输出格式如下:

  • 2 6 * * * * * *
      • 5 * 2 * * 4
      • 1 * * * * 7
  • 3 * * 2 * 1 8 *
      • 3 * 9 * * *
  • 5 4 * 1 * * 7 *
    5 * * * * 1 * * *
    6 * * 9 * 7 * * *
            • 7 5 *
              把上面的 * 替换成 1−91 - 91−9 就可以了

提醒:两个数字之间要有一个空格,其他地方不要输出多余的符号。

本题答案不唯一,符合要求的答案均正确

/*
*26******
***5*2**4
***1****7
*3**2*18*
***3*9***
*54*1**7*
5****1***
6**9*7***
******75*
*/
#include<iostream>
#include<cstdio>
using namespace std;
int maze[9][9];
void dfs(int pos);
int flag = 0;
int judge(int x,int y ,int m);
int main()
{
    char ch;
    for(int i = 0;i<9;i++)
    {
        for(int j = 0;j<9;j++)
        {
            scanf("%c",&ch);
            if(ch!='*')
                maze[i][j] = ch-'0';
            else if(ch == '*') maze[i][j] = 0;
        }
        getchar();
    }
//  for(int  i = 0;i<9;i++)
//      {
//          for(int j = 0;j<9;j++)
//          {
//              cout<<maze[i][j]<<' ';
//          }
//          cout<<endl;
//      }

    dfs(1);
    return 0;
} 
void dfs(int pos)
{
    if(flag == 1)return ;//flag的作用是表示找到一个答案即可 就停止递归 
    if(pos >81)
    {
        flag = 1;
        for(int  i = 0;i<9;i++)
        {
            for(int j = 0;j<9;j++)
            {
                cout<<maze[i][j]<<' ';
            }
            cout<<endl;
        }
        return ;
    }
    //将pos转化成x y坐标 
    int x = (pos-1)/9;//pos == 9 减一再除9还是0
    int y = pos%9-1;
    if(y==-1) y = 8;//在最后一列

    if(maze[x][y] == 0)
    {
        for(int i = 1;i<=9;i++)
        {
            if(judge(x,y,i) == 1)
            {
                maze[x][y] = i;
                dfs(pos+1);
                maze[x][y] = 0;
            }
        }
    } 
    else dfs(pos+1);

}
int judge(int x,int y,int m)
{
    for(int i = 0;i<9;i++)
    {
        if(maze[x][i] == m)
            return 0; 
    }
    for(int i = 0;i<9;i++)
    {
        if(maze[i][y] == m)
            return 0;
    }
       for(int i = x / 3 * 3;i < x / 3 * 3 + 3;++i){
        for(int j = y / 3 * 3;j < y / 3 * 3 + 3;++j){
            if(maze[i][j] == m){
                return 0;
            }
        }
    }
    return 1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值