文章目录
编程题代码仅供参考,没跑过原题数据。
编程题代码仅供参考,没跑过原题数据。
编程题代码仅供参考,没跑过原题数据。
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,m−j,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的最大值未知,无从判定时间复杂度,所以不知道应该采取怎样的策略。
以下我构思出一种暴力求解的方法:
首先对序列排序,然后相邻两项大数除以小数顺便去掉相同的数。求出来的各个值就是公比的指数次。所有这些数的最大公约数就是题目要求的答案。
本题暂时不给出代码。
编程题代码仅供参考,没跑过原题数据。
编程题代码仅供参考,没跑过原题数据。
编程题代码仅供参考,没跑过原题数据。