您的位置:首页 > 编程语言 > C语言/C++

2016年第七届蓝桥杯省赛(C/C++ A组)

2016-03-20 23:57 453 查看
版权声明:本文为博主原创文章,未经博主允许不得转载。

目录(?)[-]

父亲和儿子 枚举
生日蜡烛 枚举
填格子 DFS
快速排序
去掉尾1
四则运算 DFS
剪邮票 DFS
四方定理 枚举
回文串 区间DP最小回文代价

区间DP
最小回文代价 经典例题

最大公比

此处有目录↑

基本都是暴力搜索解决,最后两道算法题不会 - -

1.父亲和儿子 (枚举)

父亲年龄是两位数,且比儿子大27岁,问有多少种可能的情况?(父亲30岁,儿子3岁也符合题意)

直接枚举父亲年龄即可

答案是:7

[cpp] view
plain

#include <cstdio>

using namespace std;

int main() {

int ans=0;

for(int i=1;i<=9;++i)

for(int j=0;j<=9;++j)

if(10*i+j-10*j-i==27)

++ans;

printf("%d\n",ans);

}

2.生日蜡烛 (枚举)

一个人从某一岁开始每年生日都在蛋糕上插上与年龄数值相同的蜡烛,下载他总共插了236根蜡烛,问他从多少岁时开始插蜡烛?

直接从1岁开始枚举,找到答案就停止

不过这样答案是:26,后来看到网上说236也可以,这估计是个坑点

[cpp] view
plain

#include <cstdio>

using namespace std;

int solve() {

int sta=0,sum,cur;

while(1) {

sum=cur=sta;

while(sum<236)

sum+=++cur;

if(sum==236)

return sta;

++sta;

}

}

int main() {

printf("%d\n",solve());

}

3.填格子 (DFS)

有一个含有10个格子的图形,现用0~9填充,连续的数不能填充在相邻的格子中(包括对角线相邻),问有多少种填充方法?



dfs即可,注意剪枝,就能秒出

不过我认为每个数字只能填一次,算出来是:1580

[cpp] view
plain

#include <cstdio>

#include <algorithm>

using namespace std;

int grid[7][7],ans;

bool vis[11];

const int dr[4]={0,-1,-1,-1};//当前格子的正左、左上、正右、右上

const int dc[4]={-1,-1,0,1};

bool isAvailable(int r,int c,int n) {

for(int i=0;i<4;++i)

if(abs(grid[r][c]-grid[r+dr[i]][c+dc[i]])<=1)

return false;

return true;

}

void dfs(int r,int c) {

if(r==3&&c==4)

++ans;

for(int i=0;i<=9;++i) {

grid[r][c]=i;

if(!vis[i]&&isAvailable(r,c,i)) {

vis[i]=true;

int rr=r,cc=c+1;

if(cc>4) {

++rr;

cc=1;

}

dfs(rr,cc);

vis[i]=false;

}

grid[r][c]=-9;

}

}

int main() {

for(int i=0;i<7;++i) {

for(int j=0;j<7;++j) {

grid[i][j]=-9;

}

vis[i]=false;

}

vis[7]=vis[8]=vis[9]=false;

ans=0;

dfs(1,2);

printf("%d\n",ans);

}

4.快速排序

数据结构学过,这么快又忘了,还看了半天...

swap(a,p,j);

5.去掉尾1

如果一个数二进制表示时,若个位是1,则去掉从个位起开始的连续的1,若个位不是1,则不变

答案是:x&(x+1)

很简单的答案,可是当时一点都没想到,自己想的是用3元运算符,连续嵌套31次实现这个功能,由于每次代码都一样,所以用循环生成代码,最后交了700多B...

6.四则运算 (DFS)

有1~13共13个数,将12个不同的数填入下列12个空使四个运算都成立,问有多少种方法?



依旧是dfs+剪枝就能秒出,答案是:64,感觉当时写的不是64,估计当时拷代码时有地方没改 :(

[cpp] view
plain

#include <cstdio>

using namespace std;

int a[15],ans;

bool vis[15];

void dfs(int dep) {

if(dep==3) {

if(a[1]/a[2]*a[2]==a[1]&&a[1]/a[2]>0&&!vis[a[1]/a[2]]) {

vis[a[1]/a[2]]=true;

dfs(4);

vis[a[1]/a[2]]=false;

}

return ;

}

if(dep==6) {

if(a[4]*a[5]<=13&&!vis[a[4]*a[5]]) {

vis[a[4]*a[5]]=true;

dfs(7);

vis[a[4]*a[5]]=false;

}

return ;

}

if(dep==9) {

if(a[7]+a[8]<=13&&!vis[a[7]+a[8]]) {

vis[a[7]+a[8]]=true;

dfs(10);

vis[a[7]+a[8]]=false;

}

return ;

}

if(dep==12) {

if(a[10]+a[11]<=13&&!vis[a[10]+a[11]])

++ans;

return ;

}

for(int i=1;i<=13;++i) {

if(!vis[i]) {

vis[i]=true;

a[dep]=i;

dfs(dep+1);

vis[i]=false;

}

}

}

int main() {

ans=0;

dfs(1);

printf("%d\n",ans);

}

7.剪邮票 (DFS)

有一个3*4的十二生肖邮票,剪下连续的5个(对角相连不算),问有多少种方法?

dfs即可,只需要注意判重(当时先用map[已经排过序],结果不管一种剪法出现多少次都是显示为出现,最后自己写了个暴力判断才行...)

答案是:116

[cpp] view
plain

#include <cstdio>

#include <vector>

#include <algorithm>

using namespace std;

int ans;

bool vis[5][5];

struct Node {

int n;

pair<int,int> p[5];

bool operator ==(const Node& a) const {

for(int i=0;i<5;++i)

if(p[i].first!=a.p[i].first||p[i].second!=a.p[i].second)

return false;

return true;

}

};

vector<Node> tmp;

const int dr[4]={-1,0,1,0};

const int dc[4]={0,1,0,-1};

inline bool isInside(int r,int c) {

return 0<=r&&r<3&&0<=c&&c<4;

}

inline bool isOk(const Node& cur) {

for(int i=0;i<tmp.size();++i)

if(cur==tmp[i])

return false;

return true;

}

void dfs(Node cur) {

if(cur.n==5) {

sort(cur.p,cur.p+5);

if(isOk(cur)) {

++ans;

tmp.push_back(cur);

}

return ;

}

int num=cur.n++;

for(int i=0;i<num;++i) {

for(int j=0;j<4;++j) {

int rr=cur.p[i].first+dr[j],cc=cur.p[i].second+dc[j];

if(isInside(rr,cc)&&!vis[rr][cc]) {

vis[rr][cc]=true;

cur.p[num].first=rr;

cur.p[num].second=cc;

dfs(cur);

vis[rr][cc]=false;

}

}

}

--cur.n;

}

int main() {

ans=0;

Node cur;

cur.n=1;

for(int i=0;i<3;++i) {

cur.p[0].first=i;

for(int j=0;j<4;++j) {

cur.p[0].second=j;

vis[i][j]=true;

dfs(cur);

vis[i][j]=false;

}

}

printf("%d\n",ans);

}

8.四方定理 (枚举)

所有自然数至多只要用四个数的平方和就可以表示,若可以用0补齐空位,则所有自然数都可以用四个数的平方和表示,现在将这四个数按升序排序,取第一个数最小的作为答案,问答案是多少?

前面都用的dfs,所以这题当时也用了dfs的形式,但是最后没想到上限取错了,估计要wa很多数据

会做的题,就这题太遗憾了 :(

[cpp] view
plain

#include <cstdio>

#include <cmath>

using namespace std;

int a[5],tmp[5],n;

void solve() {

for(a[0]=0;a[0]<=1119;++a[0]) {//a[0]的上限为 sqrt(5000 000/4)

tmp[0]=n-a[0]*a[0];

if(a[0]>=0) {

for(a[1]=a[0];a[1]<=1291;++a[1]) {//a[1]的上限为 sqrt(5000 000/3)

tmp[1]=tmp[0]-a[1]*a[1];

if(a[1]>=0) {

for(a[2]=a[1];a[2]<=1582;++a[2]) {//a[2]的上限为 sqrt(5000 000/2)

tmp[2]=tmp[1]-a[2]*a[2];

a[3]=sqrt((double) tmp[2]);

if(a[3]>=a[2]&&a[3]*a[3]==tmp[2])

return;

}

}

}

}

}

}

int main() {

scanf("%d",&n);

solve();

printf("%d %d %d %d\n",a[0],a[1],a[2],a[3]);

}

9.回文串 (区间DP||最小回文代价)

有一个只含有A,B,C,D的字符串,问最少插入几个字符能使其成为回文串?

正解是:

①区间DP

当时不会(准确说仍然不会,以前只写过一次,完全忘了),用O(2^n)暴力,希望能骗一点点分...

待完成……

②最小回文代价 (经典例题)

计算原字符串与逆序字符串的LCS(最长公共子序列)的长度,用字符串长度减去LCS的长度就是最小回文代价

10.最大公比

给一个数列其中几项(可能会重复),求这个数列的最大公比?

还不知道正解如何做

当时想的是去重排序后,所有相邻数之间的比值的最大公约数,但是直接求最大公约数貌似会爆long long,然后就不知道怎么办了,用了一种很奇怪的方法,最后没写完交了。

转载:http://blog.csdn.net/idealism_xxm/article/details/50937688
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: