蓝桥寒假训练4->2014年第五届蓝桥杯国赛_高职组

1.好好学习

汤姆跟爷爷来中国旅游。一天,他帮助中国的小朋友贴标语。他负责贴的标语是分别写在四块红纸上的四个大字:“好、好、学、习”。但是汤姆不认识汉字,他就想胡乱地贴成一行。

请你替小汤姆算一下,他这样乱贴,恰好贴对的概率是多少?

答案是一个分数,请表示为两个整数比值的形式。例如:1/3 或 2/15 等。

如果能够约分,请输出约分后的结果。

//法一:
//排列组合公式
//法二:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int main(){
	int count=0;
	int a[4]={0,0,1,2};//代表好好学习
	do{
		count++;
	}while(next_permutation(a,a+4));
	cout<<count<<endl;
}
//注意:全排列的意思是n个不同的数
//若有相同的,即存在多重集,则全排列的结果为 去重复 后的

//1/12
2.正负金字塔

看下面的图形:

 + - + - - + - + - - + - - + -
  - - - + - - - - + - - + - -
   + + - - + + + - - + - - +
    + - + - + + - + - - + -
     - - - - + - - - + - -
      + + + - - + + - - +
       + + - + - + - + -
        + - - - - - - -
         - + + + + + +
          - + + + + +
           - + + + +
            - + + +
             - + +
              - +
               -

它是由正号和负号组成的金字塔形状。其规律是:每个符号的左上方和右上方符号如果相同,则输出为正号,否则为负号。其第一行数据由外部输入。

以下代码实现了该功能。请仔细阅读代码,并填写划线部分缺失的代码。
void f(char* x, int space, int n)
{
				int i;
				if(n<1) return;

				for(i=0; i<space; i++) printf(" ");
				for(i=0; i<n; i++) printf("%c ", x[i]);
				printf("\n");
				
				for(i=0; i<n-1; i++) x[i] = ____________________________;
				f(x,space+1,n-1);								 
}

// 用于f的测试
int test()
{
				char x[] = "+-+--+-+--+--+-";
				//char x[] = "+-+";
				f(x, 5, sizeof(x)-1);
				return 0;
}
答案:(x[i]==x[i+1]?'+':'-')

3.神奇6位数

有一个6位的正整数,它有个很神奇的性质:

分别用2 3 4 5 6去乘它,得到的仍然是6位数,并且乘积中所包含的数字与这个6位数完全一样!只不过是它们的顺序重新排列了而已。

请计算出这个6位数。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int dight[10];
int judge(int a){
	int c[10];
	memset(c,0,sizeof(c));
	if(a>999999){
		return 0;
	}
	while(a){
		c[a%10]++;
		a/=10;
	}
	for(int i=0;i<=9;i++){
		if(dight[i]!=c[i]){
			return 0;
		}
	}
	return 1;
}
int main(){
	int count;
	//cout<<1000000/6<<endl;
	for(int i=100000;i<=166667;i++){
		count=0;
		memset(dight,0,sizeof(dight));
		int t=i;
		while(t){
			dight[t%10]++;
			t/=10;
		}
		for(int j=2;j<=6;j++){
			int re=i*j;
			if(judge(re)){
				count++;
			}
			else{
				break;
			}
		}
		if(count==5){
			cout<<i<<endl;
			break;
		}
	}
	return 0;
}
//142857

4.国王的遗产

X国是个小国。国王K有6个儿子。在临终前,K国王立下遗嘱:国王的一批牛作为遗产要分给他的6个儿子。
其中,大儿子分1/4,二儿子1/5,三儿子1/6,....
直到小儿子分1/9。
牛是活的,不能把一头牛切开分。

最后还剩下11头牛,分给管家。

请计算国王这批遗产中一共有多少头牛。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int main(){
	for(int i=2520;i>=1;i--){
		int sum=i;
		for(int j=4;j<=9;j++){
			sum-=i/j;
		}
		if(sum==11){
			cout<<i<<endl;
			break;
		}
	}
	return 0;
}
//2520
5.危险系数

问题描述

抗日战争时期,冀中平原的地道战曾发挥重要作用。

地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。

我们来定义一个危险系数DF(x,y):

对于两个站点x和y (x != y), 如果能找到一个站点z,当z被敌人破坏后,x和y不连通,那么我们称z为关于x,y的关键点。相应的,对于任意一对站点x和y,危险系数DF(x,y)就表示为这两点之间的关键点个数。

本题的任务是:已知网络结构,求两站点之间的危险系数。

输入格式

输入数据第一行包含2个整数n(2 <= n <= 1000), m(0 <= m <= 2000),分别代表站点数,通道数; 接下来m行,每行两个整数 u,v (1 <= u, v <= n; u != v)代表一条通道; 最后1行,两个数u,v,代表询问两点之间的危险系数DF(u, v)。

输出格式

一个整数,如果询问的两点不连通则输出-1.

样例输入

7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6

样例输出

2
//求两点路径间的某点,去掉该点,两点间的任何路径均不连通
//思路:深搜所有可能的路径,每条路径都出现的点即为所求
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
struct node{
	int to;
	int next;
}edge[2005];
int head[1005];
int book[1005];
int path[2010];
int times[1005];
int cnt,count;
int n,m,u,v;
void Init(){
	cnt=0;
	count=0;
	memset(head,0,sizeof(head));
	memset(edge,0,sizeof(edge));
	memset(book,0,sizeof(book));
	memset(times,0,sizeof(times));
}
void Add(int x,int y){
	cnt++;
	edge[cnt].to=y;
	edge[cnt].next=head[x];
	head[x]=cnt;
}
void dfs(int x,int step){
	if(x==v){
		count++;
		for(int i=0;i<step;i++){
			times[path[i]]++;
		}
		return;
	}
	for(int i=head[x];i;i=edge[i].next){
		if(!book[edge[i].to]){
			book[edge[i].to]=1;
			path[step]=edge[i].to;
			dfs(edge[i].to,step+1);
			book[edge[i].to]=0;
		}
	}
}
int main(){
	int x,y,t=0;
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>x>>y;
		Add(x,y);
		Add(y,x);
	}
	cin>>u>>v;
	book[u]=1;
	path[0]=u;
	dfs(u,1);
	for(int i=1;i<n;i++){
		if(times[i]==count&&i!=u&&i!=v){
			t++;
		}
	}
	if(count)
		cout<<t<<endl;
	else
		cout<<-1<<endl;
	return 0;
}

6.横向打印二叉树

二叉树可以用于排序。其原理很简单:对于一个排序二叉树添加新节点时,先与根节点比较,若小则交给左子树继续处理,否则交给右子树。

当遇到空子树时,则把该节点放入那个位置。 

比如,10 8 5 7 12 4 的输入顺序,应该建成二叉树如图1所示。 

本题目要求:根据已知的数字,建立排序二叉树,并在标准输出中横向打印该二叉树。 

输入数据为一行空格分开的N个整数。 N<100,每个数字不超过10000。
输入数据中没有重复的数字。 

输出该排序二叉树的横向表示。 对应上例中的数据,应输出:
   |-12
10-|
   |-8-|
       |   |-7
       |-5-|
           |-4
为了便于评卷程序比对空格的数目,请把空格用句点代替:
...|-12
10-|
...|-8-|
.......|...|-7
.......|-5-|
...........|-4

例如:

用户输入:

10 5 20

则程序输出:

...|-20
10-|
...|-5

再例如:

用户输入:

5 10 20 8 4 7

则程序输出:

.......|-20
..|-10-|
..|....|-8-|
..|........|-7
5-|
..|-4

//建树,找规律
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
struct node{
	int num;
	struct node *left;
	struct node *right;
};
struct node *tree=NULL;
struct node *Insert(struct node *tree,int num){
	if(tree==NULL){
		tree=(struct node *)malloc(sizeof(struct node));
		tree->num=num;
		tree->left=tree->right=NULL;
	}
	else if(num>tree->num)
		tree->right=Insert(tree->right,num);
	else
		tree->left=Insert(tree->left,num);
	return tree;
}
void PrintTree(struct node *t,int loc){//loc为当前节点是其父亲的左儿子还是右儿子 1:左 2:右
	struct node *temp=tree;
	int count;
	if(!t)
		return;
	PrintTree(t->right,2);
	
	if(t!=tree){//处理第一层
		count=1;
		count+=(temp->num>9?2:1);
		for(int i=1;i<=count;i++)
			printf(".");
		if(t->num>temp->num){
			loc=2;
			temp=temp->right;
		}
		else{
			loc=1;
			temp=temp->left;
		}
	}
	while(temp!=t){//t之前的层
		if((loc==1&&temp->num<t->num)||(loc==2&&temp->num>t->num)){
			printf("|");
		}
		else{
			printf(".");
		}
		count=2;
		count+=(temp->num>9?2:1);
		for(int i=1;i<=count;i++)
			printf(".");
		if(t->num>temp->num){
			temp=temp->right;
			loc=2;
		}
		else{
			temp=temp->left;
			loc=1;
		}
	}
	//处理t
	if(t!=tree){
		printf("|-");
	}
	printf("%d",t->num);
	if(t->left||t->right){
		printf("-|");
	}
	cout<<endl;
	
	PrintTree(t->left,1);
}
int main(){
	int num;
	while(cin>>num){
		tree=Insert(tree,num);
	}
	PrintTree(tree,0);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值