• 2017年蓝桥杯B组C/C++决赛题解


    2017年蓝桥杯B组C/C++决赛题目(不含答案)

    1.36进制 ok

    求36进制,类比二进制转10进制,36^3 + 36^2 + 36^1 + 36^0

    2.磁砖样式 ok

    dfs搜索
    我自己写的答案不对dfs多搜了一些,原因是 判断条件不能连等于 例如abc==d 是错误的,已经改正

    #include <stdio.h>
    #include <string.h>
    #include <map>
    #include <algorithm>
    using namespace std;
    const int w = 3, h = 10;
    int g[w][h];
    int ans = 0;
    
    map<int, int> Hash;
    
    //检查2x2格子颜色是否相同
    bool check_color() {
        for(int i = 0; i < w; i++) 
        for(int j = 0; j < h; j++) {
            if(i+1 < w && j+1 < h) {
                if((g[i][j]+g[i][j+1]+g[i+1][j]+g[i+1][j+1]) % 4 == 0) 
                    return false;
            }
        }
        return true;
    }
    
    void dfs(int x, int y) {
        if(g[x][y] == -1) {
            //横向摆放
            if(y+1 < h && g[x][y+1] == -1) {
    
                for(int i = 0; i < 2; i++) {
                    g[x][y] = g[x][y+1] = i;
                    if(y == h-1) {  //铺下一行
                        dfs(x+1, 0);
                    } else {        //铺当前行的下一个格子
                        dfs(x, y+1);
                    }
                    g[x][y] = g[x][y+1] = -1;
                }
    
            }
            //纵向摆放
            if(x+1 < w && g[x+1][y] == -1) {
                for(int i = 0; i < 2; i++) {
                    g[x][y] = g[x+1][y] = i;
                    if(y == h-1) {  //铺下一行
                        dfs(x+1, 0);
                    } else {        //铺当前行的下一个格子
                        dfs(x, y+1);
                    }
                    g[x][y] = g[x+1][y] = -1;
                }
            }
        } else {
            if(x == w-1 && y == h-1) { //成功铺满
                if(check_color()) {
                    //判断是否出现重复情况
                    int ret = 0, bit = 1;
                    for(int i = 0; i < w; i++)
                    for(int j = 0; j < h; j++) {
                        ret += g[i][j] * bit;
                        bit *= 2;  
                    }
                    if(!Hash.count(ret)) {
                        Hash[ret] = 1;
                        ans++;
                    }
                }
                return;
            }
            if(y == h-1) {          //铺下一行
                dfs(x+1, 0);
            } else {                //铺当前行的下一个格子
                dfs(x, y+1);
            }
        }
    }
    
    int main() {
        memset(g, -1, sizeof(g));
        dfs(0, 0);
        printf("%d
    ", ans);
        return 0;
    }
    

    3.希尔伯特曲线 0%

    乱猜

    4.发现环 ok

    并查集判断环,dfs搜索环的路径
    写dfs搜索路径是重点吧,我写的都超时了。。网上搜的一份转载我改了改

    首先需要知道怎么判断环? 如不了解可以搜索:并查集判断环
    其次是dfs搜索环的路径,前面并查集判断环时找到 两个点(构成了环),dfs搜索时如果从其中一个点到达了另一个点,说明成环了,中间过程经过的点就是环的路径

    #include <stdio.h>
    #include <string.h>
    #include <vector>
    #include <algorithm>
    using namespace std;
    const int maxn = 100000+5;
    int par[maxn], vis[maxn], path[maxn];
    vector<int> edge[maxn];
    int n, s, f;
    
    //并查集 
    int find(int x) {
        return par[x] == x ? x : par[x] = find(par[x]);
    }
    
    //dfs搜索:index表示路径上第几个点 u表示当前点的编号 
    void dfs(int u, int index) {
        path[index] = u;//记录路径 
        if(u == f) {
            sort(path, path + index + 1);//按题目要求先排序从小到大输出 
            for(int i = 0; i <= index; i++) {
                printf("%d%c", path[i], i==index?'
    ':' ');
            }
            return;
        }
        vis[u] = 1; //标记点已经用过 
        for(int i = 0; i < edge[u].size(); i++) {
            int v = edge[u][i];
            if(!vis[v]) dfs(v, index+1);
        }
        vis[u] = 0; //回溯
    }
    
    int main() {
        while(scanf("%d", &n) == 1) {
            int u, v;
            for(int i = 1; i <= n; i++) par[i] = i;
            for(int i = 0; i < n; i++) {
                scanf("%d%d", &u, &v);
                int ru = find(u), rv = find(v);
                if(ru == rv) s = u, f = v; //并查集找到两个端点 (构成环) 
                else {
                    par[ru] = rv;
                    edge[u].push_back(v);
                    edge[v].push_back(u);
                }
            }
            memset(vis, 0, sizeof(vis));
            dfs(s, 0);
        }
        return 0;
    }
    

    5.对局匹配 ok

    30%:暴力,dfs暴力搜也行
    50%:贪心
    100%:先分组,再dp求出每一组的最大值,dp[i]表示前i个组的最大值;
    什么是一组?
    怎么求最大值?用到题意:相邻的两份不能都取 比如 x x+k x+2k 你只能按x+k 或者 x x+2k的数量取

    贪心做法50%:

    #include<bits/stdc++.h>
    using namespace std;
    
    /*
    贪心:竟然能过50%数据
    统计每个数出现的次数
    从1~n小到大,计算可以匹配的 i 和 i+k 中取最小值,(贪心:当前这个人不用就浪费了!所以用完他,但是这种思路是错的:有可能后面的人和后面的人+k匹配时答案更优)
    特判k=0的时候 
    */
    
    
    const int maxn = 100005;
    int cnt[2*maxn];
    int a[maxn];
    int n,k;
    int ans = 0;
    
    
    int main(){
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]),cnt[a[i]]++;
    	
    	if(k==0){
    		for(int i=1;i<=n;i++) ans += cnt[i]/2;
    	}else{
    		for(int i=1;i<=n;i++){
    			int minx = min(cnt[i],cnt[i+k]);
    			cnt[i] -= minx;
    			cnt[i+k] -= minx;
    			ans += minx;
    		}
    	}
    
    	printf("%d",n - ans);
    	return 0;
    } 
    

    dp做法AC:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #define MAX_SCORE 100000
    using namespace std;
    const int maxn = 100000 + 5;
    int cnt[MAX_SCORE+5], val[maxn], dp[maxn];
    int n, k;
    
    
    /*
    设共有x种分数,将其分为k组,每个分数满足相邻的分数值相差为k。
    正如样例2中所示,共有4种分数,
    将其分为1组:{1,2,3,4},这个组中任何相邻的两个分数都不能同时取,
    因为它们相差k,该分组还对应了一个人数分组:{4,1,1,4},要想使得人数尽量多,
    而且分数不能相差1,那么选择分数分别为{1,4},人数是4+4=8.
    
    上述是只有一个分组的情况,
    当有多个分组的时候也是同样的处理方法--尽量选择不相邻且人数最多。
    对于一个人数分别为{a1,a2,...,an}的分组,可以利用动态规划算法来选择最多人数,且都不相邻。
    每个ai只有选择与不选择两种可能,
    假设dp(i)表示前i个人数能获得的最多人数,那么选择第i个人数的话,dp(i)=dp(i-2)+ai,
    如果不选择第i个人数的话,dp(i)=dp(i?1),这样得到转移方程dp(i)=max{dp(i-1),dp(i-2)+ai}。
    
    注意,当k=0的时候特殊处理一下。
    
    */ 
    
    int main() {
        while(scanf("%d%d", &n, &k) == 2) {
            memset(cnt, 0, sizeof(cnt));
            int score, ans = 0;
            for(int i = 1; i <= n; i++) {
                scanf("%d", &score);
                cnt[score]++;
            }
            //特殊处理k=0的情况
            if(k == 0) {
                for(int i = 0; i <= MAX_SCORE; i++) {
                    if(cnt[i]) ans++;
                }
            } 
            else {
            	//共k份 
                for(int i = 0; i < k; i++) {
                    int m = 0;
                    //取得每一组 初始x为i 后面就是x+k x+2k x+3k ...
                    for(int j = i; j <= MAX_SCORE; j+=k) {
                        val[m++] = cnt[j];
                    }
                    dp[0] = val[0];
                    for(int j = 1; j < m; j++) {
                        if(j == 1) dp[j] = max(dp[0], val[j]);
                        else dp[j] = max(dp[j-2] + val[j], dp[j-1]);
                    }
                    ans += dp[m-1];
                }
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    /*
    10 1 
    2 1 1 1 1 4 4 3 4 4
    */ 
    

    6.观光铁路 0%

    读不懂
    网上搜到两份博客解析这道题:
    https://blog.csdn.net/weixin_40839812/article/details/79769757
    https://blog.csdn.net/BUAA_Alchemist/article/details/86768839#
    本文参考至:https://www.cnblogs.com/flyawayl/

  • 相关阅读:
    java 数组
    数组(二)
    JVM内存分配策略
    JVM垃圾收集算法
    LINUX 查看硬件配置命令
    遗传算法
    svn简单使用
    Several concepts in Data Mining
    JVM判断对象存活的算法
    JVM运行时数据区
  • 原文地址:https://www.cnblogs.com/fisherss/p/10876262.html
Copyright © 2020-2023  润新知