写在前面的话,蓝桥杯快要开始了。毕竟参加了就得做些准备,今天开始做一些题目练习一下,为4月1号的比赛做些准备。
题目见:http://blog.csdn.net/Dodd9199/article/details/50936774
第一题:
简单的求和题。
#include<iostream>
#include<cmath>
using namespace std;
int a[110];
int main(){
int i;
int sum=0;
a[1]=1;
for(i=1;i<100;i++){
a[i+1]=a[i]+i+1;
}
for(i=1;i<=100;i++){
sum+=a[i];
}
cout<<sum<<endl;
return 0;
}
第二题:
暴力,i,j分别代表起点和终点,遍历求解,简单题。
也可以利用等差数列求和公式,求出以i开头,j结尾等差数列的和。然后遍历i,j看能不能让sum恰好等于236
#include<iostream>
#include<cmath>
using namespace std;
int a[110];
int ans=0;
bool flag=false;
int main(){
int i,j;
for(i=1;i<=100;i++){
ans=i;
for(j=i+1;j<=100;j++){
ans+=j;
if(ans==236){
flag=true;
break;
}
}
if(flag) break;
}
cout<<i<<endl;
return 0;
}
第三题:
填数字问题,这里很巧妙的运用了C++中的next_permutation(a,a+n);生成1-9的全排列。(注意头文件#include<algorithm>
)
开始这道题目写错了,那个p,q是double类型,开始写成了int类型,所以一直是错的。以后注意类型问题。
还要注意的事情是,next_permutation生成全排列的时候注意要先给数组赋值。比如a={1,3,4,5};
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int a[11];
int ans=0;
void init(){
int i;
for(i=0;i<9;i++){
a[i]=i+1;
}
}
void Solve(){
do{
double p=1.0*a[1]/a[2];
double q=1.0*(100*a[3]+10*a[4]+a[5])/(100*a[6]+10*a[7]+a[8]);
if(a[0]+p+q==10){
ans++;
}
}while(next_permutation(a,a+9));
}
int main(){
init();
Solve();
cout<<ans<<endl;
return 0;
}
第四题:程序填空-快速排序
刚刚学了快速排序算法的原理,算法思路就是:
先选定一个基数,通常选定第一个数就可以;
分别从左到右和从右到左遍历,从右向左遍历,使得左边的数都小于基数,右边的数都大于基数;再把基数查到对应的位置
这样一个数组就分成两端,重复。
这篇博客讲的非常好:
http://blog.csdn.net/kwang0131/article/details/51085734
swap(a,j,p)
第五题:程序填空-递归
对于f(int a[],int k,int m,char b[]).a[] 是每个国家的最多指派人数,k表示当前是哪个国家,m表示还需要派送几个人(可以为负数).b表示已经派送的人的字符串。
所以这个题目在递归中间的的 第一个循环表示从0~a[i]中让i国选择指派人数,内循环只是向b[]记录的过程。
f(a,k+1,m-i,b)
第六题:
dfs先填数然后判断周围是否可行,八数码问题。
#include<iostream>
#include<cmath>
using namespace std;
int map[3][4];
int vis[10];
int flag[3][4];
int dir[8][2]={1,0,0,1,0,-1,-1,0,-1,-1,1,1,1,-1,-1,1};
int ans=0;
void init(){
int i,j;
for(i=0;i<3;i++){
for(j=0;j<4;j++){
flag[i][j]=1;
}
}
flag[0][0]=0;
flag[2][3]=0;
memset(vis,0,sizeof(vis));
}
void Solve(){
int i,j;
int dx,dy;
bool book=true;
for(i=0;i<3;i++){
for(j=0;j<4;j++){
if(flag[i][j]==0) continue;
for(int k=0;k<8;k++){
dx=i+dir[k][0];
dy=j+dir[k][1];
if(dx<0||dx>=3||dy<0||dy>=4||flag[dx][dy]==0) continue;
if(abs(map[dx][dy]-map[i][j])==1){ book=false;break; }
}
}
}
if(book){ans++;}
}
void dfs(int index){
int x=index/4;
int y=index%4;
if(x==3){
Solve();
return ;
}
if(flag[x][y]){
for(int i=0;i<10;i++){
if(!vis[i]){
vis[i]=1;
map[x][y]=i;
dfs(index+1);
vis[i]=0;
}
}
}
else{
dfs(index+1);
}
}
int main(){
init();
dfs(0);
cout<<ans<<endl;
return 0;
}
暴力,依旧可以用生成全排列的方法先填数,然后再判断是否行可行。next_penutation(a,a+n);
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int a[10]={1,2,3,4,5,6,7,8,9,10};
int ans=0;
int main(){
do{
int q1=abs(a[0]-a[1])-1;
int q2=abs(a[0]-a[3])-1;
int q3=abs(a[0]-a[4])-1;
int q4=abs(a[0]-a[5])-1;
int q5=abs(a[1]-a[2])-1;
int q6=abs(a[1]-a[5])-1;
int q7=abs(a[1]-a[6])-1;
int q8=abs(a[2]-a[6])-1;
int q9=abs(a[3]-a[4])-1;
int q10=abs(a[3]-a[7])-1;
int q11=abs(a[3]-a[8])-1;
int q12=abs(a[4]-a[8])-1;
int q13=abs(a[4]-a[5])-1;
int q14=abs(a[4]-a[9])-1;
int q15=abs(a[5]-a[6])-1;
int q16=abs(a[5]-a[9])-1;
int q17=abs(a[1]-a[4])-1;
int q18=abs(a[2]-a[5])-1;
int q19=abs(a[4]-a[7])-1;
int q20=abs(a[5]-a[8])-1;
int q21=abs(a[6]-a[9])-1;
int q22=abs(a[7]-a[8])-1;
int q23=abs(a[8]-a[9])-1;
if((q1&&q2&&q3&&q4&&q5&&q6&&q7&&q8&&q9&&q10&&q11&&q12&&q13&&q14&&q15&&q16&&q17&&q18&&q19&&q20&&q21&&q22&&q23)!=0){
ans++;
}
}while(next_permutation(a,a+10));
cout<<ans<<endl;
return 0;
}
第七题:剪邮票问题
开始写这道题目的时候一直不知道怎么判断5个数是不是连在一起。参考别人的思路终于搞懂了这道题目。
首先先用stl中的next_permutation生成5组数。
然后dfs判断是否相连。
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
if(!vis[i][j]&&ai[i][j]){
num++;
dfs(i,j);
}
}
if(num==1) sum++;
这个部分写的非常有趣。它的意思是如果我一次dfs遍历过后,如果存在被标记为1的a[i][j](及我们涂色的方格)没有被访问过,那么证明这次我们涂得颜色不相连。应为一次dfs把所有相连的格子都标记了。
#include"iostream"
#include"algorithm"
#include"string.h"
using namespace std;
int ai[3][4];
int bi[12]={0,0,0,0,0,0,0,1,1,1,1,1};
bool vis[3][4];
int num;
int sum=0;
int dir[4][2]={1,0,-1,0,0,-1,0,1};
void dfs(int r,int c){
if(r<0 ||r>=3||c<0||c>=4) return ;
if(vis[r][c]||!ai[r][c]) return ;
vis[r][c]=true;
for(int i=0;i<4;i++){
int x=r+dir[i][0];
int y=c+dir[i][1];
dfs(x,y);
}
}
int main(){
do{
memset(vis,false,sizeof(vis));
num=0;
int flag=0;
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
ai[i][j]=bi[flag++];
}
}
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
if(!vis[i][j]&&ai[i][j]){
num++;
dfs(i,j);
}
}
}
if(num==1) sum++;
}while(next_permutation(bi,bi+12));
cout<<sum<<endl;
return 0;
}
第八题:四平方和问题
暴力,可以开一个三层遍历,第四层的数可以用总和减去求出来。(如果遍历四层就会爆掉,==先前写错了哎)
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int N;
bool flag=false;
int main(){
int i,j,k;
double p;
cin>>N;
for(i=0;i*i<N;i++){
for(j=i;j*j<N;j++){
for(k=j;k*k<N;k++){
int q=N-i*i-j*j-k*k;
//判断q是不是平方数
p=sqrt(q);
if(p==int(p)){ flag=true; break;}
}
if(flag) break;
}
if(flag) break;
}
cout<<i<<" "<<j<<" "<<k<<" "<<p<<endl;
return 0;
}
第九:交换瓶子
贪心。
将要求瓶子的序号存储在数组B中,遍历数组A,如果A中当前位置的瓶子序号不对,就交换当前位置的瓶子和要求序号瓶子的位置。记下交换次数。
#include<iostream>
using namespace std;
#define maxn 100010
int a[maxn],b[maxn];
int ans=0;
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
b[i]=i+1;
}
for(int i=0;i<n;i++){
if(a[i]!=b[i])
{
int temp;
for(int j=0;j<n;j++)
{
if(a[j]==b[i])
{
temp=a[j];
a[j]=a[i];
a[i]=temp;
ans++;
break;
}
}
}
}
cout<<ans<<endl;
return 0;
}
第十:不会