最后水一篇2016蓝桥杯C/C++省赛B组的题解


编程题代码仅供参考,没跑过原题数据。
编程题代码仅供参考,没跑过原题数据。
编程题代码仅供参考,没跑过原题数据。

T1_煤球数目(简单数学)

——题目描述——
在这里插入图片描述
——解——
等差数列求和得出的数列,再进行一次求和。推公式也可以,但敲代码快一点。
答案:171700



——Code——

#include<iostream>
using namespace std;
int main()
{
	int sum=0,ans=0;
	for(int i=1;i<=100;++i)
	{
		sum+=i;
		ans+=sum;
	}
	cout<<ans<<endl;
	return 0;
} 




T2_生日蜡烛(尺取法)

——题目描述——
在这里插入图片描述
——解——
依然是一个等差数列,怀疑自己走错片场了…
套等差数列求和公式就可以了。
分两种情况,2月29日生日或其它普通日子。
可以得出三个答案26,116,236,挑一个看起来正常的。
最终填:26



——Code——

#include<iostream>
using namespace std;
int main()
{
	int tot=236;
	int sum=0;
	int i=0,j=0;
	while(j<=236)
	{
		while(sum<tot)
		{
			++j;
			sum+=j; 
		}
		while(sum>tot&&i<j)
		{
			sum-=i;
			++i;
		}
		if(sum==tot)
		{
			cout<<i<<endl;
			++j;
			sum+=j;
		}
	}
	i=0;j=0;
	sum=0;
	while(j<=236)
	{
		while(sum<tot)
		{
			j+=4;
			sum+=j;
		}
		while(sum>tot&&i<j)
		{
			sum-=i;
			i+=4;
		}
		if(sum==tot)
		{
			cout<<i<<endl;
			j+=4;
			sum+=j;
		}
	}
	return 0;
}




T3_凑算式(DFS)

——题目描述——
在这里插入图片描述
——解——
本质上是一个全排列问题,用深度优先搜索可以轻松解决。
找一个排列A~I,满足上面的式子,一共有 9 ! 9! 9!种情况。
答案:29



——Code——

#include<iostream>
using namespace std;
bool vis[10];
int a[10];
int ans;
void dfs(int step)
{
	if(step==10)
	{
		int num1=a[1];
		int num2=a[2];
		int num3=a[3];
		int num4=a[4]*100+a[5]*10+a[6];
		int num5=a[7]*100+a[8]*10+a[9];
		if((num2*num5+num3*num4)%(num3*num5)!=0) return;
		if(num1+(num2*num5+num3*num4)/(num3*num5)!=10) return;
		++ans;
		return;
	}
	for(int i=1;i<=9;++i)
		if(vis[i]==false)
		{
			vis[i]=true;
			a[step]=i;
			dfs(step+1);
			vis[i]=false;
			a[step]=0;
		}
}
int main()
{
	dfs(1);
	cout<<ans<<endl;
	return 0;
}




T4_快速排序(二分)

——题目描述——
在这里插入图片描述

#include <stdio.h>

void swap(int a[], int i, int j)
{
    int t = a[i];
    a[i] = a[j];
    a[j] = t;
}

int partition(int a[], int p, int r)
{
    int i = p;
    int j = r + 1;
    int x = a[p];
    while(1){
        while(i<r && a[++i]<x);
        while(a[--j]>x);
        if(i>=j) break;
        swap(a,i,j);
    }
    ______________________;
    return j;
}

void quicksort(int a[], int p, int r)
{
    if(p<r){
        int q = partition(a,p,r);
        quicksort(a,p,q-1);
        quicksort(a,q+1,r);
    }
}

int main()
{
    int i;
    int a[] = {5,13,6,24,2,8,19,27,6,12,1,17};
    int N = 12;

    quicksort(a, 0, N-1);

    for(i=0; i<N; i++) printf("%d ", a[i]);
    printf("\n");

    return 0;
}

——解——
18年也考了快速排序
答案: s w a p ( a , p , j ) swap(a,p,j) swap(a,p,j)



T5_抽签(普通搜索)

——题目描述——
在这里插入图片描述

#include <stdio.h>
#define N 6
#define M 5
#define BUF 1024

void f(int a[], int k, int m, char b[])
{
    int i,j;

    if(k==N){ 
        b[M] = 0;
        if(m==0) printf("%s\n",b);
        return;
    }

    for(i=0; i<=a[k]; i++){
        for(j=0; j<i; j++) b[M-m+j] = k+'A';
        ______________________;  //填空位置
    }
}
int main()
{   
    int  a[N] = {4,2,2,1,1,3};
    char b[BUF];
    f(a,0,M,b);
    return 0;
}

——解——
明确各个变量的作用,a数组限定每个国家派遣上限,b数组保存答案。k对国家进行遍历,m对派遣对剩余人数进行遍历。按普通的搜索题推理就可以了。
答案: f ( a , k + 1 , m − j , b ) f(a,k+1,m-j,b) f(a,k+1,mj,b)



T6_方格填数(DFS)

——题目描述——
在这里插入图片描述
——解——
又是一道全排列问题,用深度优先搜索排列完之后,填入格子中,再对每个数字的周围8格检查。
答案:1580



——Code——

#include<iostream>
using namespace std;
int mp[4][5];
bool vis[10];
int a[10];
int dx[8]={-1,0,1,1,1,0,-1,-1};
int dy[8]={-1,-1,-1,0,1,1,1,0};
int ans;
int check()
{
	int k=0;
	for(int i=1;i<=3;++i)
		for(int j=1;j<=4;++j)
		{
			if((i==1&&j==1)||(i==3&&j==4)) continue;
			mp[i][j]=a[k++];
		}
	for(int i=1;i<=3;++i)
		for(int j=1;j<=4;++j)
		{
			if((i==1&&j==1)||(i==3&&j==4))continue;
			for(int d=1;d<8;++d)
			{
				int x=dx[d]+i;
				int y=dy[d]+j;
				if(x>=1&&x<=3&&y>=1&&y<=4&&(mp[x][y]==mp[i][j]+1||mp[x][y]==mp[i][j]-1))
					return 0;
			}
		}
	return 1;
}
void dfs(int step)
{
	if(step==10)
	{
		ans+=check();
		return;
	}
	for(int i=0;i<=9;++i)
		if(!vis[i])
		{
			vis[i]=true;
			a[step]=i;
			dfs(step+1);
			vis[i]=false;
		}
}
int main()
{
	for(int i=0;i<=4;++i)
		mp[0][i]=999;
	for(int i=0;i<=3;++i)
		mp[i][0]=999;
	mp[1][1]=mp[3][4]=999;
	dfs(0);
	cout<<ans<<endl;
	return 0;
}




T7_剪邮票(BFS)

——题目描述——
在这里插入图片描述
——解——
先用组合数排列出可能的选择,然后对每一种选择用一次广度优先搜索检查连通性。
答案:116



——Code——

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
vector<int> edge[13];
bool vis[13];
queue<int> q;
int ans;
void check()
{
	bool cpyvis[13];
	for(int i=1;i<=12;++i)
		cpyvis[i]=vis[i];
	for(int i=1;i<=12;++i)
		if(cpyvis[i])
		{
			q.push(i);
			break;
		}
	while(!q.empty())
	{
		int node=q.front();
		q.pop();
		for(int i=0;i<edge[node].size();++i)
		{
			if(cpyvis[edge[node][i]])
			{
				q.push(edge[node][i]);
				cpyvis[edge[node][i]]=false;
			}
		}
	}
	int p;
	for(p=1;p<=12;++p)
		if(cpyvis[p]==true)
			break;
	if(p==13) ++ans;
}
void search(int step,int cnt)
{
	if(cnt==6)
	{
		check();
		return;
	}
	if(step==13) return;
	for(int i=step;i<=12;++i)
	{
		vis[i]=true;
		search(i+1,cnt+1);
		vis[i]=false;
	}
}
int main()
{
	for(int i=1;i<=12;++i)
	{
		if(i!=1&&i!=5&&i!=9) edge[i].push_back(i-1);
		if(i!=4&&i!=8&&i!=12) edge[i].push_back(i+1);
		if(i>4) edge[i].push_back(i-4);
		if(i<9)	edge[i].push_back(i+4);
	}
	search(1,1);
	cout<<ans<<endl;
}




T8_四平方和(有技巧的搜索)

——题目描述——
在这里插入图片描述
——解——
这道题的难点在于怎么利用小技巧控制搜索时间。
以下是我的优化策略:
①把小于5000000的平方数都装进一个数组并标记(1e3)
②把两个平方数的和标记出来(1e6)
③对前两个数进行枚举,考察n减去前两个平方数和是否已被标记,如果已被标记,进入下一步(1e6)
④再枚找到平方和等于步骤③中被标记数的后两个数字(1e6)
总时间复杂度控制在1e7~1e8,一般情况下可以在1000ms内解决。



——Code——

#include<iostream>
using namespace std;
bool vis[5000006];
int q[3003];
int n;
int main()
{
	cin>>n;
	int len;
	for(int i=0;i*i<=n;++i)
	{
		vis[i*i]=true;
		q[i]=i*i;
		len=i;
	}
	for(int i=0;i<len;++i)
		for(int j=1;q[i]+q[j]<=n;++j)
			vis[q[i]+q[j]]=true;
	for(int i=0;i<len;++i)
		for(int j=0;q[i]+q[j]<=n/2;++j)
			if(vis[n-q[i]-q[j]])
			{
				for(int p=len-1;p>=0;--p)
					for(int k=p;q[k]+q[p]>=n/2;--k)
						if(q[k]+q[p]==n-q[i]-q[j])
						{
							cout<<i<<" "<<j<<" "<<k<<" "<<p<<endl;
							return 0;
						}
			}
	return 0;		
}




T9_交换瓶子(贪心)

——题目描述——
在这里插入图片描述
——解——
本题考虑贪心,一般这种答案无序并且要求最优解的题都可以考虑这种方法。
一次交换最多只能使两个瓶子恢复原位,那么要使转换次数经量少,就要尽可能的交换序号对调的瓶子。当把这些瓶子都调换完之后,剩下的就是完全无序的瓶子。除去之前已经交换完瓶子,二次交换最多可以解决三个序号对调的瓶子,因此要尽可能找到三个序号对调的瓶子。于是,考虑三次交换最多可以解决四个序号对调的瓶子,可以这么理解,把其中一个调换到正确的位置,那么就退化成三个无序瓶子或两两对调序号的情况了,以此类推。
我们要做的就是找到这些对调环,最少的交换次数就是所有环的长度减1并且求和。



——Code——

#include<iostream>
using namespace std;
int a[10004];
bool vis[10004];
int n;
int ans;
void search(int node)
{
	vis[node]=true;
	++ans;
	if(!vis[a[node]])
		search(a[node]);
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		cin>>a[i];
		if(a[i]==i) vis[i]=true;
	}
	for(int i=1;i<=n;++i)
		if(vis[i]==false)
		{
			search(i);
			--ans;
		}
	cout<<ans<<endl;
	return 0;
}




T10_最大比例(数论,不确定数据规模)

——题目描述——
在这里插入图片描述
——解——
本题N的最大值未知,无从判定时间复杂度,所以不知道应该采取怎样的策略。
以下我构思出一种暴力求解的方法:
首先对序列排序,然后相邻两项大数除以小数顺便去掉相同的数。求出来的各个值就是公比的指数次。所有这些数的最大公约数就是题目要求的答案。
本题暂时不给出代码。

编程题代码仅供参考,没跑过原题数据。
编程题代码仅供参考,没跑过原题数据。
编程题代码仅供参考,没跑过原题数据。

18年链接
17年链接

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值