7/13
洛谷P2437
题目描述 一只蜜蜂在下图所示的数字蜂房上爬动,已知它只能从标号小的蜂房爬到标号大的相邻蜂房,现在问你:蜜蜂从蜂房 mmm 开始爬到蜂房 nnn,m<nm<nm<n,有多少种爬行路线?(备注:题面有误,右上角应为 n−1n-1n−1)PS:此题我之前做过一摸一样的,通过找规律发现蜜蜂到达n点的时候有两种路线:一种是从a[n-2]到a[n],另一种是a[n-1]到a[n](这种情况以及包含了从a[n-2]到a[n-1]); 公式:a[n]=a[n-1]+a[n-2];
但是我发现在进行循环的时候程序运行停止了,才发现是数据太大的原因。如何毅然决然选择用大数去做。
#include<iostream>
#include<string>
using namespace std;
string Fibonaci[1000+5]; //本题是大数所以需要用字符串数组经行加法运算
string Fibonaci_num(const string&a,const string&b)
{
int t=0,i;
string c=a; //将a赋值给c(主要是让a的长度大小赋给c,以便计算)
for(i=0;i<c.size();i++)
{
if(i<b.size()) //b的长度是小于a的长度
{
c[i]=(b[i]-'0'+a[i]-'0'+t)%10+'0';
a[i]-'0'+b[i]-'0'+t<10?t=0:t=1;
}
else
{
c[i]=(a[i]-'0'+t)%10+'0';
a[i]-'0'+t<10?t=0:t=1;
}
}
if(t) c=c+'1'; //进1操作
return c;
}
int main()
{
int m,n;
Fibonaci[0]="1";Fibonaci[1]="1";
for(int i=2;i<=1000;i++)
Fibonaci[i]=Fibonaci_num(Fibonaci[i-1],Fibonaci[i-2]);
while(cin>>m>>n)
{
for(int i=Fibonaci[n-m].size()-1;i>=0;i--)
cout<<Fibonaci[n-m][i];
cout<<endl;
}
return 0;
}
***7/14号,今天做了一道递归题目,这题是通过蓝书上面一道题目思想而想出来的。
P1164 小A点菜
题目描述 不过uim由于买了一些辅(e)辅(ro)书,口袋里只剩M元(M≤10000)。
餐馆虽低端,但是菜品种类不少,有N种(N≤100),第i种卖ai元(ai≤1000)。由于是很低端的餐馆,所以每种菜只有一份。
小A奉行“不把钱吃光不罢休”,所以他点单一定刚好吧uim身上所有钱花完。他想知道有多少种点菜方法。
由于小A肚子太饿,所以最多只能等待1秒
输入 #1
4 4
1 1 2 2
输出 #1
3
PS:这题问的是要有多少种情况 那么我们就要把选和不选的情况都考虑在内。
比如随便一道菜我可以选,也可以不选。如果选 那要考虑选了之后 我是否超过了总钱数。如果不选 那就跳过这道菜。按照这样的情况走下去直到等于或者超过总钱数,若超过则return,若没有超过sum++。
#include<iostream>
using namespace std;
int a[105],n,sum=0;
void order(int m,int num)
{
if(num==0) {sum++; return;} //退出条件
else if(num<0) return;
for(int i=m;i<=n;i++)
{
num-=a[i]; //选择a[i]这盘菜
order(i+1,num); //对下一盘菜进行同样选择
num+=a[i]; //回溯不选
}
}
int main()
{
int sumnum;
cin>>n>>sumnum;
for(int i=1;i<=n;i++)
cin>>a[i];
order(1,sumnum);
cout<<sum;
return 0;
}
思考:这题主要是利用函数递归一步一步去求解,把每一种情况都考虑到。每一道菜可以选也可以不选,让我想到了八皇后递归题目,我一开始想这题为什么会一个数组怎么会输出多行数,为什么会突然变了。这就是回溯的力量。
7/16号 今天做了一道题目P1873 是一到二分题目,题目容易读懂,基本思路也出来了,主要是题目看漏了一个地方。
#include<iostream>
#include<cstdio>
using namespace std;
long a[1000000+5];
long long m,n;
void Find_tree(long left,long right,const long long m)
{
while(left<=right)
{
long long sum=0;
long mid=left+(right-left)/2;
for(int i=0;i<n;i++)
if(a[i]>mid)
sum+=a[i]-mid;
/*if(sum==m) {cout<<mid;return;}*/ //为什么输出这个就错了(因为题目是要求你大于等于M而不是必须等于M)
if(sum<m)
right=mid-1;
else
left=mid+1;
}
cout<<left-1; //而这个却是对的?
}
int main()
{
cin>>n>>m;
long max=-1;
for(long i=0;i<n;i++)
{
cin>>a[i];
if(max<a[i]) max=a[i];
}
Find_tree(1,max,m);
}
PS:两个注释的地方就是错误所在,一直在wa不知道哪错了,后来看了题解才发现就那么小小的地方出现了错误,还是自己看题不太仔细啊!
洛谷P1223 接水问题
这道题以前做过类似的,具体想法如下:在一段数列A中,先将A从小到大排序:因为如果A[i]大于后面n个数,将A[i]和A[n+i]替换则n个人等待时间会减小(因为自身接水时间不算),按照局部解最优的情况下应该要时数列A从小到大排序在计算,这样才会总的等待时间最小。
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef struct{
int next,num; //next 表示下标
}water;
water w[1000+5];
int cmp(const water&a,const water&b)
{
return a.num<b.num; //这里排序是如果相等,则下标保持不变
}
int main()
{
int n;
double sum=0;
cin>>n;
for(int i=1;i<=n;i++)
{
w[i].next=i;
cin>>w[i].num;
}
sort(w+1,w+n+1,cmp);
int t=0;
for(int i=1;i<=n;i++)
{
cout<<w[i].next<<" ";
t+=w[i-1].num; //注意这里是加上前一个的时间,而不是这个自己的时间
sum+=t;
}
cout<<endl;
printf("%.2lf",sum/n);
}
PS:这道题整体比较简单,做了一到水题。