蓝桥杯:历年试题倒是比较适合打基础。
开始一天一年真题,大约一个星期,恰好去上大检验一下,有什么变化。一定要完成啊 ,否则。。。还谈什么其他的。
还可以看一下这样的效果如何,是否需要改进。计划还是要写一下,更容易落实。主要不要有侥幸心理。
下周是正规课对应的习题,具体到时候确定大概计划。
//引用,真他的厉害:在我的团队里,聚集了一批这样的天才人物。目前Face++ 团队成员共60 个左右,其中超过80% 来自清华,80% 以上是工程师,30 多个人至少曾获得过一项世界级编程比赛奖项,得过国际奥林匹克竞赛金牌的有7 个,大多数成员有海外留学和专业机构工作的背景。
//大二上学期或大三上学期参加ACM区域赛,放再这里警醒自己。
2017
1.迷宫
dfs+暴力,主要考察代码熟练度。每一个遍历一下,因为要计数(在没有规律的前提下,当然是要遍历了),然后找临界,环是不行的,到达边的时候就代表可以出去。
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
string a[10];//要会使用string,使用
bool vis[12][12];//尽量用bool数组
bool dfs(int i,int j){
if(vis[i][j]) return false ;
if(i<0||i>9||j<0||j>9) return true;
vis[i][j]=1;
switch(a[i][j]){
case 'U':
return dfs(i+1,j);
case 'D'://要用单引号
return dfs(i-1,j);
case 'E':
return dfs(i,j-1);
case 'R':
return dfs(i,j+1);
default:
return false;
}
}
int main(){
a[0]="UDDLUULRUL";//双引号
a[1]="UURLLLRRRU";//使用char的话不可以用这样的初始化
a[2]="RRUURLDLRD";
a[3]="RUDDDDUUUU";
a[4]="URUDLLRRUU";
a[5]="DURLRLDLRL";
a[6]="ULLURLLRDU";
a[7]="RDLULLRDDD";
a[8]="UUDDUDUDLL";
a[9]="ULRDLUURRR";//初始化可以一行行的
int ans=0;
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
memset(vis,0,sizeof(vis));
if(dfs(i,j)){
ans++;
}
}
}
cout<<ans<<endl;
return 0;
}
答案为10
2.跳蚱蜢
由于排列有限,至少经过多少次的话一般是BFS,模拟还是比较难的。代码答案为40(忘记对不对了
#include<iostream>
#include<cstdio>
#include<queue>
#include<set>
#include<cstring>
#include<algorithm>
using namespace std;
struct stateandlevel{
char *state;
int pos0,level;
stateandlevel(char *ss,int lee,int poss):state(ss),level(lee),pos0(poss){}
};
struct cmp{//struct
bool operator()(char *a,char *b){
return strcmp(a,b)<0;
}
};
queue<stateandlevel>q;
set<char*,cmp> allstate;
char *start={"012345678"};
char *target="087654321";
void swap(char *a,int pos,int pos0){
char t=a[pos];
a[pos]=a[pos0];
a[pos0]=t;
}
void addnei(char *s,int pos,int newpos,int le){
char *new_state=(char*)malloc(9*sizeof(char));
strcpy(new_state,s);
swap(new_state,pos,newpos);
if(allstate.find(new_state)==allstate.end()){
allstate.insert(new_state);
q.push(stateandlevel(new_state,le+1,newpos));
}
}
int main(){
q.push(stateandlevel(start,0,0));
while(!q.empty()){
stateandlevel ans=q.front();
char *state=ans.state;
int le=ans.level;
int pos=ans.pos0;
if(strcmp(state,target)==0){
cout<<le<<endl;
return 0;
}
int new_pos=(pos-1+9)%9;
addnei(state,pos,new_pos,le+1);
new_pos=(pos-2+9)%9;
addnei(state,pos,new_pos,le+1);
new_pos=(pos+1+9)%9;
addnei(state,pos,new_pos,le+1);
new_pos=(pos+2+9)%9;
addnei(state,pos,new_pos,le+1);
q.pop();
}
}
D:\xiaotingting\Untitled1.cpp|22|warning: deprecated conversion from string constant to 'char*'|
D:\xiaotingting\Untitled1.cpp|23|warning: deprecated conversion from string constant to 'char*'|
||=== Build finished: 0 errors, 2 warnings ===|
要会适当忽略错误
3.方格填数
答案为2686
要学会用check单独处理,然后对换后一个个再回溯 或者用全排列,也是一种常见题型。
#include<iostream>
#include<algorithm>
using namespace std;
int a[10]={0,1,2,3,4,5,6,7,8,9};
bool check(){
if(abs(a[0]-a[1])==1||abs(a[0]-a[3])==1||abs(a[0]-a[4])==1||abs(a[0]-a[5])==1||abs(a[1]-a[2])==1||abs(a[1]-a[4])==1||abs(a[1]-a[5])==1||abs(a[1]-a[6])==1||abs(a[2]-a[5])==1||abs(a[2]-a[6])==1||
abs(a[3]-a[4])==1||abs(a[3]-a[7])==1||abs(a[3]-a[8])==1||abs(a[4]-a[5])==1||abs(a[4]-a[7])==1||abs(a[4]-a[8])==1||abs(a[4]-a[9])==1||abs(a[5]-a[6])==1||abs(a[5]-a[8]==1)||abs(a[5]-a[9])==1||
abs(a[6]-a[9])==1||abs(a[7]-a[8])==1||abs(a[8]-a[9])==1){//可枚举
return false;
}
return true;
}
int ans;
void f(int k){
if(k==10){
if(check()){
ans++;
}
}
for(int i=k;i<=9;i++){//包括本身
int t=a[k];
a[k]=a[i];
a[i]=t;
f(k+1);//递归
t=a[k];
a[k]=a[i];
a[i]=t;//回溯
}
}
int main(){
f(0);
cout<<ans<<endl;
return 0;
}
4.快速排序
#include<iostream>
#include<algorithm>
using namespace std;
void swap(int a[],int i,int j){
int t=a[i];
a[i]=a[j];
a[j]=t;
}
int partition(int a[],int i,int j){
int q=i;
int r=j+1;//后面会多减
int p=a[q]; //因为到后面i会变,所以
while(1){
while(q<j&&a[++q]<p) ;//范围 ,不是q<r会死循环的
while(a[--r]>p) ;
if(q>=r) break;//先后决定是否会重复换
swap(a,q,r);
}
swap(a,i,r);
return r;
}
void quicksort(int a[],int i,int j){
if(i<j)//i==j就没必要写了,容易不严谨
{
int p=partition(a,i,j);
quicksort(a,i,p-1);
quicksort(a,p+1,j);
}
}
int main(){
int a[8]={1,5,3,2,4,9,7,5};
quicksort(a,0,7);
for(int i=0;i<=7;i++){
cout<<a[i]<<" ";
}
return 0;
}
是道填空题,但是自己写还是错了挺久的细节。快速排序为基础,而且涉及二指针和三指针等等变种,也需要了解。
5.字母组串
是递归题,同样也是填空题
#include<iostream>
#include<cstdio>
using namespace std;
int f(int a,int b,int c,int n){//组成多少个长度n的字符串
if(a<0||b<0||c<0) return 0 ;//先后
if(n==0) return 1;
return f(a-1,b,c,n-1)+f(a,b-1,c,n-1)+f(a,b,c-1,n-1);//数量同时要减一
}
int main (){
cout<<f(1,1,1,2)<<endl;
cout<<f(1,2,3,3)<<endl;
return 0;
}
6.最大公共子串
#include<iostream>
#include<cstdio>
using namespace std;
#define N 256
int c[N][N];
int maxx;
int f(const char*a,const char *b){
maxx=0;
memset(c,0,sizeof(int)*N*N);
int len1=strlen(a);
int len2=strlen(b);
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
if(a[i-1]==b[j-1]) {//注意初始化
c[i][j]=c[i-1][j-1]+1;
if(maxx<c[i][j]){
maxx=c[i][j];
// cout<<maxx<<endl;
}
}
}
}
return maxx;
}
int main(){
printf("%d\n",f("abefcd","becd"));
return 0;
}
简单的动态规划
可以超出
7.正则问题
主要是理解问题,还有就是代码的熟练度了
细节总是出错,事实证明,我做每一道题若不是有十足的把握,起码要有三个自己写的例子来检验
#include<iostream>
#include<cstdio>
using namespace std;
char a[100];
int temp;
int m;//存储最大
int pos;//位置变化
int len;
int f(){
m=0;temp=0;//初始化
//int len=strlen(a);
while(pos<len){
if(a[pos]=='('){
// temp=0;
pos++;
// cout<<temp<<endl;
int poss=f();//
// cout<<poss<<endl;//属于临时变量
temp=temp+poss;
//cout<<temp<<endl;
}
else if(a[pos]=='x'){
//m++;
temp++;
pos++;
}
else if(a[pos]==')'){
m=max(m,temp);
// cout<<m<<endl;
temp=0;//注意要清零,否则会继续
pos++;
return m;
}
else if(a[pos]=='|'){
m=max(m,temp);
temp=0;
pos++;
//m=max(m,)
}
}
m=max(m,temp);
return m;
}
int main(){
scanf("%s",a);
len=strlen(a);
// cout<<len<<endl;
int res=f();
cout<<res<<endl;
return 0;
}
错了很久的说。
8.包子凑数
要会适当推广,不是系数的最大公倍数不是1的话,凑不出来的就有INF个,然后再用背包思想去做。去凑
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6;
int a[maxn];
bool b[maxn];
int main(){
int n;int g;
cin>>n;
b[0]=true;
for(int i=1;i<=n;i++){
cin>>a[i];
if(i==1){
g=a[i];
}
else {
g=__gcd(g,a[i]);
}
for(int j=0;j<10000;j++){//有个公式可以估计范围,来确定答案 a*b-a-b
if(b[j]){
b[j+a[i]]=true;//无限个嘛,完全背包
}
}
}
if(g!=1){
cout<<"INF"<<endl;
return 0;
}
int ans=0;
for(int i=0;i<10000;i++){
if(!b[i]){
ans++;
}
}
cout<<ans<<endl;
return 0;
}
数学公式的使用,类比于完全背包之类的
9.分巧克力
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6+1;
int h[maxn];
int ll[maxn];
int main(){
int n,k;
cin>>n>>k;int ans=0;
for(int i=1;i<=n;i++){
cin>>h[i]>>ll[i];
}
int l=1;int r=100001;
while(l<=r){
int mid=(l+r)>>1;int cnt=0;
for(int i=1;i<=n;i++){
cnt+=(h[i]/mid)*(ll[i]/mid);
}
if(cnt>=k){
l=mid+1;
ans=mid;//可再加一个变量
}
else {
r=mid-1;
}
}
cout<<ans<<endl;
return 0;
}
二分,反正主要是我没基础的话,写对是件需要长时间练习的事。(而且由于是我
10.油漆面积
这道题目可以暴力过,一开始的话也许?//主要是要思维开阔些,冷静些
但是个线段树的扫面线+矩形的模板题
估计要和这题僵持很久了
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=1e4+2;
bool p[maxn][maxn];
void paint(int x1,int y1,int x2,int y2){
for(int i=x1;i<x2;i++){
for(int j=y1;j<y2;j++){//
p[i][j]=1;
}
}
}
int main(){
int n;int x1,x2,y1,y2;
cin>>n;
for(int i=1;i<=n;i++){
cin>>x1>>y1>>x2>>y2;
paint(x1,y1,x2,y2);
}
int sum=0;
for(int i=0;i<10001;i++){
for(int j=0;j<10001;j++){
if(p[i][j]){
sum++;
}
}
}
cout<<sum<<endl;
return 0;
}
N堆石子排成一列,两两合并成一堆,只能相邻的合并。合并代价为两堆石子个数之和。总的代价为所有中间结果之和。
思路是: 本问题实际上就是哈夫曼编码,每次选择最小的两堆合并,合并的代价总和就是最终的最小代价,可以借助小根堆实现
首先这道题目特殊在于总的次数是一定的,那么每一次都选最小的话,虽然是在变化后的数组选的,但是依旧是原数组的第几大,若是分开来的话。
油漆面积
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e4;
//写了很久依旧不对,好吧,留在这里,留待以后解决吧
struct line{
int x1,x2,h,f;//入边,出边
line(){}
line(int x11,int x22,int hh,int ff):x1(x11),x2(x22),h(hh),f(ff){ }
bool operator<(const line&l)const{
return h<l.h;
}
}lines[N];
int x[N<<1];//记录所有横坐标
struct segtree{
int pl,pr,cnt,len;
segtree():cnt(0),len(0){}
segtree *lson,*rson;
};//
segtree *buildtree(int pl,int pr){
segtree *t=new segtree();
t->pl=pl;
t->pr=pr;
if(pl==pr) return t;
int mid=(pl+pr)>>1;
t->lson=buildtree(pl,mid);
t->rson=buildtree(mid+1,pr);
return t;
}
void updatelength(segtree*ptree,int tl,int tr){
if(ptree->cnt){
ptree->len=x[tr]-x[tl-1];//
}
else if(tr==tl){
ptree->len=0;
}
else {
ptree->len=ptree->lson->len+ptree->rson->len;//负数
}
}
void update(segtree *t,int pl,int pr,int value){
int tl=t->pl;
int tr=t->pr;
if(tl<=pl&&tr>=pr){
t->cnt+=value;
updatelength(t,pl,pr);
return ;
}
int mid=(tl+tr)>>1;
// if()
if(pl<=mid){
update(t->lson,pl,pr,value);
}
if(mid<pr) update(t->rson,pl,pr,value);//有相交的地方
updatelength(t,tl,tr);
// rre
}
int ans;
int main(){
int n;
cin>>n;
int x1,y1,x2,y2;
int index=0;
for(int i=0;i<n;i++){
cin>>x1>>y1>>x2>>y2;
x[index]=x1;
lines[index]=line(x1,x2,y1,1);index++;
x[index]=x2;
lines[index]=line(x1,x2,y2,-1);
index++;
}
sort(x,x+index);
sort(lines,lines+index);
int x_end=unique(x,x+index)-x;
segtree *root=buildtree(1,x_end);//末尾取不到 ,建树
for(int i=0;i<index;i++){
int pl=lower_bound(x,x+x_end,lines[i].x1)-x;
int pr=lower_bound(x,x+x_end,lines[i].x2)-x;//两次出现
update(root,pl+1,pr,lines[i].f);
ans+=root->len*(lines[i+1].h-lines[i].h);
}
cout<<ans<<endl;
return 0;
}
终于明白一拳打倒棉花上的感觉了。
还有到了第二天,根本没完成计划内的事,太失败了。