蓝桥杯 2013 C++ A 题解 只记录部分题,2013所有题的网盘链接 T4 标题: 颠倒的价牌 T8 买不到的数  T9 标题:剪格子   T10 标题:大臣的旅费

链接:https://pan.baidu.com/s/1C4pZkgw5XTeMEvn6okas5g
提取码:qe26

T4 标题: 颠倒的价牌


小李的店里专卖其它店中下架的样品电视机,可称为:样品电视专卖店。

其标价都是4位数字(即千元不等)。

小李为了标价清晰、方便,使用了预制的类似数码管的标价签,只要用颜色笔涂数字就可以了(参见p1.jpg)。

蓝桥杯 2013 C++ A 题解
只记录部分题,2013所有题的网盘链接
T4 标题: 颠倒的价牌
T8 买不到的数
 T9 标题:剪格子
  T10 标题:大臣的旅费

这种价牌有个特点,对一些数字,倒过来看也是合理的数字。如:1 2 5 6 8 9 0 都可以。这样一来,如果牌子挂倒了,有可能完全变成了另一个价格,
比如:1958 倒着挂就是:8561,差了几千元啊!!

当然,多数情况不能倒读,比如,1110 就不能倒过来,因为0不能作为开始数字。

有一天,悲剧终于发生了。某个店员不小心把店里的某两个价格牌给挂倒了。并且这两个价格牌的电视机都卖出去了!

庆幸的是价格出入不大,其中一个价牌赔了2百多,另一个价牌却赚了8百多,综合起来,反而多赚了558元。

请根据这些信息计算:赔钱的那个价牌正确的价格应该是多少?


答案是一个4位的整数,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。

#include <iostream>
#include <sstream>
#include <vector>

using namespace std;

void i2s(int num, string &str) {
    stringstream ss;
    ss << num;
    ss >> str;
}

void s2i(string &str, int &num) {
    stringstream ss;
    ss << str;
    ss >> num;
}

char to(char x) {
    if (x == '6')return '9';
    else if (x == '9')return '6';
    else return x;
}

string reverse(const string &str) {
    string ans;
    for (int i = 3; i >= 0; --i) {
        ans.insert(ans.end(), to(str[i]));
    }
    return ans;
}

struct price {
    int a, b, c;//原始价格,错误价格,差
};
vector<price> v1;//存储-200多的
vector<price> v2;//存储+800多的

int main(int argc, const char *argv[]) {
//    cout<<reverse("1958")<<endl;
// 枚举所有四位数中可以颠倒的
//将其颠倒过来,与原来的数值做差,将-200多和+800的记录下来,分别记录在两个集合中
//遍历两个集合将-+两两求和,结果为558的即为正确答案
    for (int i = 1000; i < 10000; ++i) {
        string str;
        i2s(i, str);
        if (str.find('3') != string::npos || str.find('4') != string::npos || str.find('7') != string::npos ||
            str.rfind('0') == 3)
            continue;
        string r = reverse(str);
        int r_int;
        s2i(r, r_int);//r_int就是翻转后的价格,i是原始价格
        int plus = r_int - i;
        if (plus > -300 && plus < -200) {
            price p = {i, r_int, plus};
            v1.push_back(p);
        } else if (plus > 800 && plus < 900) {
            price p = {i, r_int, plus};
            v2.push_back(p);
        }

//        此时,v1存储了-200多的,v2存储了+800多的
        for (int i = 0; i < v1.size(); ++i) {
            for (int j = 0; j < v2.size(); ++j) {
                if (v1[i].c + v2[j].c == 558) {
                    printf("%d %d %d %d %d %d
", v1[i].a, v1[i].b, v1[i].c, v2[j].a, v2[j].b, v2[j].c);
                }
            }
        }

    }
    return 0;
}

  

T8 买不到的数

标题:买不到的数目

小明开了一家糖果店。他别出心裁:把水果糖包成4颗一包和7颗一包的两种。糖果不能拆包卖。

小朋友来买糖的时候,他就用这两种包装来组合。当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。

你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是17。大于17的任何数字都可以用4和7组合出来。

本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。

输入:
两个正整数,表示每种包装中糖的颗数(都不多于1000)

要求输出:
一个正整数,表示最大不能买到的糖数

不需要考虑无解的情况

例如:
用户输入:
4 7
程序应该输出:
17

再例如:
用户输入:
3 5
程序应该输出:
7


资源约定:
峰值内存消耗 < 64M
CPU消耗 < 3000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。

//ax+by=C,不定方程的解 a=4,b=7,C=17 这种情况下,xy实际上有解,7*2+(7-4)==3*7 -1*4
//a,b互质,一定有解且解的数目无穷 *******************************************************
//C是gcd(a,b)的倍数,方程一定有解,而且有无穷多解

//条件:一定有解=》a,b互质
//条件2:xy都是大于等于0的整数,在这个限定条件下有的C是无解的,那么C的上界是多少呢?至多是a*b

#include <iostream>
#include <set>

using namespace std;

int main(int argc, const char *argv[]) {
    int a, b;
    scanf("%d %d", &a, &b);
    set<int> ss;
//    枚举a*x+b*y的值,上边界是a*b
    for (int x = 0; a * x <= a * b; ++x) {
        for (int y = 0; a * x + b * y <= a * b; ++y) {
            ss.insert(ss.end(), a * x + b * y);
        }
    }
    for (int i = a * b; i >= 0; --i) {
        if (ss.find(i) == ss.end())//i不在set中,那么i就是答案
        {
            printf("%d
", i);
            break;
        }
    }
    return 0;
}

  

 T9 标题:剪格子


如图p1.jpg所示,3 x 3 的格子中填写了一些整数。


蓝桥杯 2013 C++ A 题解
只记录部分题,2013所有题的网盘链接
T4 标题: 颠倒的价牌
T8 买不到的数
 T9 标题:剪格子
  T10 标题:大臣的旅费

 蓝桥杯 2013 C++ A 题解
只记录部分题,2013所有题的网盘链接
T4 标题: 颠倒的价牌
T8 买不到的数
 T9 标题:剪格子
  T10 标题:大臣的旅费

我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是60。

本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。
如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。
如果无法分割,则输出 0

程序输入输出格式要求:
程序先读入两个整数 m n 用空格分割 (m,n<10)
表示表格的宽度和高度
接下来是n行,每行m个正整数,用空格分开。每个整数不大于10000
程序输出:在所有解中,包含左上角的分割区可能包含的最小的格子数目。


例如:
用户输入:
3 3
10 1 52
20 30 1
1 2 3

则程序输出:
3

再例如:
用户输入:
4 3
1 1 1 1
1 30 80 2
1 1 1 100

则程序输出:
10

(参见p2.jpg)


资源约定:
峰值内存消耗 < 64M
CPU消耗 < 5000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。

 #include<stdio.h> 
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#define mk(i,j) make_pair(i,j)
using namespace std;

int m, n;
int total;
int g[10][10];
int ans;
/*抽象了一种剪辑方法*/
class Cut {
public:
    set<pair<int, int> > grids;//包含若干格子
    int sum;//所有格子的数值的求和
};
/**
 * 将st中的元素拷贝到新set中
 * @param st
 * @return
 */
set<pair<int, int> > copySet(set<pair<int, int> > &st) {
    set<pair<int, int> >::iterator iter = st.begin();
    set<pair<int, int> > ans;
    while (iter != st.end()) {
//        重新mkpair,加入新set中
        ans.insert(*iter);
        iter++;
    }
    return ans;
}
void add(int sum, int i, int j, set<pair<int, int> > &grids, Cut *&cut_new) {
    const pair<int, int> &pair_n = make_pair(i , j);
//                    深度拷贝set
    set<pair<int, int> > grids_copy=copySet(grids);
    grids_copy.insert(pair_n);
    cut_new->grids=grids_copy;
    cut_new->sum=sum+g[i][j];
}
vector<Cut *> vs[100];//分别存储格子数为1~100的各种剪法

int main(int argc, const char *argv[]) {
    scanf("%d %d", &m, &n);
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            scanf("%d", &g[i][j]);
            total += g[i][j];
        }
    }
//    第一个格子就是一半
    if (g[0][0] == total / 2) {
        printf("%d
", 1);
        return 0;
    }

    /*左上角格子,只有一种剪法,加入v[1]*/
    Cut *c = new Cut();
    const pair<int, int> p = make_pair(0, 0);
    c->grids.insert(p);
    c->sum = g[0][0];
    vs[1].push_back(c);//只包含一个格子且包含00的只有一种剪法

    for (int i = 2; i <= m * n; ++i) {
//        i是格子数,用vs[i-1]里面的来生成
//迭代vs[i-1]里面的所有剪法
        for (int j = 0; j < vs[i - 1].size(); ++j) {
//            pCut代表一种剪辑方法
            Cut *pCut = vs[i - 1][j];
//            这种剪辑方法里面记录了所有格子,这些格子每个都扩展一个,即形成个数+1的剪法
            set<pair<int, int> > &grids = pCut->grids;
            int sum = pCut->sum;
            set<pair<int, int> >::iterator iter = grids.begin();
//            迭代所有的格子,尝试添加它的邻居
            while (iter != grids.end()) {
                const pair<int, int> &p = *iter;//代表一个格子的坐标
                int x=p.first;
                int y=p.second;

                if(x+1<n&&grids.find(mk(x+1,y))==grids.end()){//下方,能走通且下方格子不在当前集合中

                    Cut *cut_new=new Cut();//生成一个新的剪法
                    add(sum, x+1, y, grids, cut_new);//将原有的格子全部拷入,再增加当前试探的新的格子
                    if(cut_new->sum==total/2){
                        printf("%d
", i);
                        return 0;
                    }else if(cut_new->sum<total/2)
                        vs[i].push_back(cut_new);
                }
                if(x-1>=0&&grids.find(mk(x-1,y))==grids.end()){//上方
                    Cut *cut_new=new Cut();
                    add(sum, x-1, y, grids, cut_new);
                    if(cut_new->sum==total/2){
                        printf("%d
", i);
                        return 0;
                    }else if(cut_new->sum<total/2)
                    vs[i].push_back(cut_new);
                }
                if(y+1<m&&grids.find(mk(x,y+1))==grids.end()){//右方
                    Cut *cut_new=new Cut();
                    add(sum, x, y+1, grids, cut_new);
                    if(cut_new->sum==total/2){
                        printf("%d
", i);
                        return 0;
                    } else if(cut_new->sum<total/2)
                    vs[i].push_back(cut_new);
                }
                if(y-1>=0&&grids.find(mk(x,y-1))==grids.end()){//左方
                    Cut *cut_new=new Cut();
                    add(sum, x, y-1, grids, cut_new);
                    if(cut_new->sum==total/2){
                        printf("%d
", i);
                        return 0;
                    }else if(cut_new->sum<total/2)
                    vs[i].push_back(cut_new);
                }
                iter++;
            }
        }
    }
    printf("%d
", 0);
    return 0;
}

  T10 标题:大臣的旅费

很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。

为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者
通过其他大城市间接到达。

同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。

J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。
他有一个钱袋,用于存放往来城市间的路费。

聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,
在走第x千米到第x+1千米这一千米中(x是整数),
他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。

J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?

输入格式:
输入的第一行包含一个整数n,表示包括首都在内的T王国的城市数
城市从1开始依次编号,1号城市为首都。
接下来n-1行,描述T国的高速路(T国的高速路一定是n-1条)
每行三个整数Pi, Qi, Di,表示城市Pi和城市Qi之间有一条高速路,长度为Di千米。

输出格式:
输出一个整数,表示大臣J最多花费的路费是多少。

样例输入:
5
1 2 2
1 3 1
2 4 5
2 5 4

样例输出:
135

样例说明:
大臣J从城市4到城市5要花费135的路费。


根据资源限制尽可能考虑支持更大的数据规模。


资源约定:
峰值内存消耗 < 64M
CPU消耗 < 5000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。

//本题求树的直径
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;

int n;

class Point {
public:
    int num, cost;//点的编号,和到这个点的距离
};

int ans;

void f(vector<Point> m[], int vis[], int i, int j, int dis) {
//查看是否直接邻居
    vector<Point> nei_i = m[i];//i的邻居的集合
    for (int k = 0; k < nei_i.size(); k++) {
        if (nei_i[k].num == j)//i的直接邻居中有j
        {
            ans = max(ans, dis + nei_i[k].cost);
            return;
        }
    }

    vis[i] = 0;
//    不是直接邻居,就从现有的直接邻居去连接
    for (int k = 0; k < nei_i.size(); k++) {
        int num = nei_i[k].num;
        if (vis[num] == -1)
            f(m, vis, num, j, dis + nei_i[k].cost);
    }
    vis[i] = -1;
}
int pnt=-1;
void dfs(vector<Point> m[], int vis[], int start,int dis) {
    vector<Point> nei_i = m[start];//i的邻居的集合
    vis[start]=0;
    bool isLeaf=true;
    for (int k = 0; k < nei_i.size(); k++) {
        int num = nei_i[k].num;//邻居点的标号
        if (vis[num] == -1){
            isLeaf= false;
            dfs(m, vis, num,dis + nei_i[k].cost);
        }
    }
    vis[start]=-1;
    if(isLeaf){
        if(dis>ans){
            ans=dis;
            pnt=start;
        }
    }
}
int dis2money(int dis) {
    return 11 * dis + dis * (dis - 1) / 2;
}

int main(int argc, const char *argv[]) {
    scanf("%d", &n);
    vector<Point> m[n + 1];
    int vis[n + 1];
    memset(vis, -1, sizeof(vis));//初始化为-1
    for (int i = 0; i < n - 1; ++i) {
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        Point p1 = {b, c};
        Point p2 = {a, c};
        m[a].push_back(p1);
        m[b].push_back(p2);
    }
/*1.暴力,求任意两点间距离,并维护最长距离*/
    /*for (int i = 1; i <= n - 1; ++i) {
        for (int j = i + 1; j <= n; ++j) {
//            int ans_t = ans;
            f(m, vis, i, j, 0);
//            if (ans > ans_t) {
//            cout << i << " " << j << " " << ans << endl;
//            }
        }
    }*/

    dfs(m,vis,1,0);
    ans=0;
    dfs(m,vis,pnt,0);
//    printf("%d
", pnt);
    printf("%d
", dis2money(ans));
//    printf("%d
", ans);
    return 0;
}