文章目录
前言:
题目来源于这里
第一题:回溯法是什么?我用三层for循环写的,看了别的博主的,似乎因为数组小而并没有爆掉
第二题:我用的动规,并且不会用vector
#include <iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[100010];
int dp[10010]={};
int main()
{
int n,d,max=0;
scanf("%d%d",&n,&d);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
sort(a,a+n);
//dp[0]=1;
for(int i=1;i<n;i++){
for(int j=0;j<i;j++){
if((a[i]-a[j]>=d||a[i]-a[j]<=-d)&&dp[i]<dp[j]+1){
dp[i]=dp[j]+1;
}
}
}
for(int i=0;i<n;i++){
if(max<dp[i]){
max=dp[i];
}
}
if(max==0){
printf("0\n");
}
else{
printf("%d",max+1);//如果存在的话,还要算上第一个数
}
return 0;
}
第三题:我没考虑到后一个同学到达时无人在排队的边界情况(前三共耗时59min)
#include <iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
struct Student{
long a;//到达时间
long t;//打饭耗时
long b;//等待时间上限
long start;//开始打饭时间
long leave;//离开时间
int flag=0;//没有离开
}student[100010];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%ld%ld%ld",&student[i].a,&student[i].t,&student[i].b);
}
if(n>0){ //至少有一个人来吃饭了
student[0].start=student[0].a;
student[0].leave=student[0].start+student[0].t;//离开时间=开始时间+打饭耗时
}
for(int i=1;i<n;i++){
if(student[i].a+student[i].b>=student[i-1].leave){//若i同学等待上限时间点不小于i-1同学结束打饭时间点
student[i].start=student[i-1].leave;
student[i].leave=student[i].start+student[i].t;//离开时间=开始时间+打饭耗时
}
else{ //提前离开了
student[i].leave=student[i-1].leave;
student[i].flag=1;//离开了的标记
}
}
for(int i=0;i<n;i++){
if(student[i].flag!=1){//没有离开
printf("%ld",student[i].start);
}
else{
printf("-1");
}
if(i<n-1) printf(" ");
}
return 0;
}
第四题:晕晕,因为我忘记树怎么写了,只能用一维数组存树,空间复杂度o(2^n)我去!!(做完1、2、3、4共用时2h2min)
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
int tree[500010]={};
int sum=0;
int n;//A的长度
void visit(int i){
if(tree[2*i]!=0){//有左孩子
visit(2*i);
}
if(tree[i]!=0){
if(i==1){
printf("0");
}
else{
printf("%d",tree[i/2]);
}
}
sum++;
if(sum<n) printf(" ");
if(tree[2*i+1]!=0){
visit(2*i+1);
}
}
int main()
{
scanf("%d",&n);
if(n>0) scanf("%d",&tree[1]);
for(int i=2;i<=n;i++){
int temp;
scanf("%d",&temp);
for(int j=1;j<pow(2,n);){
if(temp>tree[j]){
if(tree[2*j+1]==0){//有空位
tree[2*j+1]=temp;
break;
}
else{
j=2*j+1;
}
}
else{
if(tree[2*j]==0){//有空位
tree[2*j]=temp;
break;
}
else{
j=2*j;
}
}
}
}
visit(1);
return 0;
}
第五题:光想就想了好久,我没意识到这个是动规,自己按数学题做了,答案好像是对的,abs()是求绝对值(共耗时3h8min)
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
int a[100010];
int b[100010];
int dp[100010]={};//以i结尾的元素前面有多少个连续大于ave_A取下界的元素
int dp_change[100010]={};//记录b数组中哪些元素改变过
int main()
{
int n;//A的长度
int sum_A=0,quanzhi=0;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
sum_A+=a[i];
}
int ave_A=sum_A/n;
for(int i=0;i<n;i++){
b[i]=ave_A;
if(a[i]>ave_A){
dp[i]=dp[i-1]+1;
}
}
for(int i=0;i<n;i++){
if(dp[i]==2){//存在连续两个大于平均值下界的时候,b[j]++,平方项权值最多只会增加2,而绝对值权值会减小>=2,能使整体权值减小
int j;
for(j=i-1;dp[j]>0&&j<n;j++){
b[j]++;
dp_change[j]=1;
}
i=j+1;
}
}
//边界大于平均值下界而倒数第二个不大于时,其本身权值变动可抵消,但是可以规避大-小-大,平方项权值+2的问题
//末尾边界
if(dp[n-2]==0&&dp[n-1]==1){
b[n-1]++;
dp_change[n-1]=1;
}
//起始边界
if(dp[1]==0&&dp[0]==1){
b[0]++;
dp_change[0]=1;
}
for(int i=1;i<n-1;i++){//出现大-小(i)-大情况时,将b[i]加一可以使平方项权值-2,而绝对值项权值只会+1,使总体权值-1
if(dp_change[i]==0&&dp_change[i-1]==1&&dp_change[i+1]==1){
b[i]++;
dp_change[i]=1;
i++;
}
}
for(int i=0;i<n;i++){
if(b[i]-a[i]>0){
quanzhi=quanzhi+b[i]-a[i];
}
else{
quanzhi=quanzhi-b[i]+a[i];
}
}
for(int i=0;i<n-1;i++){
if(b[i]!=b[i+1]){
quanzhi++;//因为b数组的值只有正负1的波动
}
//quanzhi=quanzhi+pow(b[i]-b[i+1],2);
}
printf("%d\n",quanzhi);
printf("he");
return 0;
}
总结:
- 复习树怎么写
- 复习文件输入输出
- 复习vector等stl的写法(vector最常用)
- 复习动规