1、The Lost Cow(lostcow)
【问题描述】
FJ发现他的明星牛Bessie走失了,他需要找到她!
幸运的是,农场只有一条长途径,而FJ知道Bessie肯定在这条路上的某个地方。路径是一条数轴,FJ现在位于x,而Bessie目前在位置y(FJ不知道)。如果FJ知道Bessie所在的地方,他可以直接走到她身边,旅行一段距离| x-y |。不幸的是,外面已经是黑夜,FJ看不到任何东西。他能找到Bessie的唯一方法是来回走动,直到他最终达到Bessie的位置。
试图找出在他的搜索中来回走走的最佳策略,FJ咨询计算机科学研究文献,有趣的发现,这个确切的问题是居然是计算机科学家过去的研究,被称为“失食奶奶问题”(这其实是真的!)。
FJ找到Bessie的推荐解决方案是移动到位置x + 1,然后反向并移动到位置x-2,然后又移动到位置x+ 4,……,以“之字形”模式,每一步距离他以前的初始起始位置两倍。这种方法保证他将在最差行驶9倍距离| x-y |之内可以找到Bessie。给定x和y,请计算他将根据上述之字形搜索策略行走的总路程,直到找到Bessie。
【输入格式】(lostcow.in):
一行输入包含两个不同的空格分隔的整数x和y。两者都在0 ... 1,000范围内。
【输出格式】(lostcow.out):
一行输出,其中包含FJ找到Bessie行走的总路程。
【输入样例】
3 6
【输出样例】
9
思路:这道题是一道简单的模拟题,照着题目去模拟就可以了。
参考程序:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int ans,a[1001];
int main()
{
freopen("lostcow.in","r",stdin);
freopen("lostcow.out","w",stdout);
int x,y,d=1,k;
cin>>x>>y;
k=x;
for(int i=0;i<=1000;i++)
a[i]=i;
for(int i=1;i<=1000;i++)
{
int c;
if(i%2!=0)
{
c=a[x+d];
for(int j=k+1;j<=c;j++)
{
if(j==y)
{
ans++;
cout<<ans;
return 0;
}
else
ans++;
}
k=c;
d=d*2;
}
if(i%2==0)
{
c=a[x-d];
for(int j=k-1;j>=c;j--)
{
if(j==y)
{
ans++;
cout<<ans;
return 0;
}
else
ans++;
}
k=c;
d=d*2;
}
}
}
反思:这道题当时只有80分,原因:运行时错误,不知道什么原因。
2、输油管道问题(pipe)
【问题描述】
某石油公司计划建造一条由东向西的主输油管道。该管道要穿过一个有n 口油井的油田。从每口油井都要有一条输油管道沿最短路径(或南或北)与主管道相连。如果给定n口油井的位置,即它们的x 坐标(东西向)和y 坐标(南北向),应如何确定主管道的最优位置,即使各油井到主管道之间的输油管道长度总和最小的位置?证明可在规定时间内确定主管道的最优位置。
给定n 口油井的位置,编程计算各油井到主管道之间的输油管道最小长度总和。
【输入格式】pipe.in
第1 行是油井数n,1≤n≤10000。
接下来n 行是油井的位置,每行2个整数x和y,-10000≤x,y≤10000。
【输出格式】pipe.out
第1 行中的数是油井到主管道之间的输油管道最小长度总和。
【输入样例】
5
1 2
2 2
1 3
3 -2
3 3
【输出样例】
6
反思:这道题可以用把坐标全都画出来,不难发现,其实最合适就是最大的y坐标和最小的y坐标中的中位数。再统计每个y坐标到油管的位置就行了。
参考程序:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int ans,maxn,minn,y[100005];
int main()
{
freopen("pipe.in","r",stdin);
freopen("pipe.out","w",stdout);
int n;
cin>>n;
for(int i=0;i<n;i++)
{
int x;
cin>>x>>y[i];
}
sort(y,y+n);
maxn=y[n/2];
for(int i=0;i<n;i++)
{
y[i]=y[i]-maxn;
if(y[i]>=0)
ans=ans+y[i];
else
if(y[i]<=0)
ans=ans+abs(y[i]);
}
cout<<ans;
return 0;
}
反思:这道题注意审题。
3、探险(explore)
【问题描述】
有n个同学一起去探险,现在把n个同学分成k个小组,每个小组完成一项探险任务。分组时,如果第i人到第j人分在同一组(i<j),则他们之间的所有人(第i+1,i+2,…,j-1个)也必须在同一个小组中。
一个小组内所有人的体力和越小,途中可能越危险。为了确保每个同学的安全,要求分组时,使得所有小组中,体力和最小的那个小组的所有人的体力和尽量大。
依次告诉你每个人的体力,如何分组呢?
【输入格式】explore.in
第1行有两个正整数n(1<=n<=30000)和k(1<=k<=1000),用一个空格分隔。
第2行有n个用空格分隔的正整数,表示n个人的体力值。
【输出格式】explore.out
只有1行,该行只有一个整数,表示最佳划分方案中,最弱的小组中,所有人的体力值之和。
思路:这道题看数据量就只不能用枚举的方法,这道题我们可以确定答案的范围,而且答案有单调性,所以我们可以用二分答案。所以我们只要判断二分的答案是否为最大。
参考程序:
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,maxn,ans,w[150005];
int isok(int x)
{
int k=0,sum=0;
for(int i=1;i<=n;i++)
{
sum=sum+w[i];
if(sum>=x)
{
k++;
sum=0;
}
}
return k;
}
int main()
{
freopen("explore.in","r",stdin);
freopen("explore.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>w[i];
maxn+=w[i];
}
int l=1,r=maxn+1;
while(l+1<r)
{
int mid=(l+r)/2;
if(isok(mid)<m)
r=mid;
else
l=mid;
if(isok(mid)==m)
ans=max(ans,mid);
}
cout<<ans;
return 0;
}
反思:二分题注意答案范围和闭区间,其实二分答案最重要的就是判断函数的编写。
4、兔子繁殖(rabbit)
【问题描述】
兔子有很强的繁殖能力。1对成年的兔子每个月可以生育一对幼年的兔子,而1对幼年的兔子经过m个月之后,就会长成1对成年的兔子。当一开始有1对成年兔子时,经过d个月以后,共有多少对兔子。你的任务是计算出一对成年兔子经过d个月后,共有多少对兔子,假设整个过程中没有兔子死亡。
【输入格式】rabbit.in
输入有多组数据,每组数据有1行,为两个整数m(1≤m≤10),d(1≤d≤100),当m=d=0时表示结束。
【输出格式】rabbit.out
每行为每组数据对应最后得到的兔子数。
【输入样例】
2 3
3 5
0 0
【输出样例】
5
9
思路:这道题是递推题,找到这道题的边界是1—m天都生一只,因为一开始就有一只成年兔子,然后就是上个月兔子的总数+当前月份-m个月的兔子总数=当前月份的兔子数。即f(n)=f(n-1)+f(i-m);
参考程序:
#include<iostream>
#include<cstdio>
using namespace std;
long long f[100005];
int main()
{
freopen("rabbit.in","r",stdin);
freopen("rabbit.out","w",stdout);
int m,d;
while(cin>>m>>d)
{
if(!m && !d)
break;
memset(f,0,sizeof(f));
f[0]=1;
for(int i=1;i<=m;i++)
f[i]=i+1;
for(int i=m+1;i<=d;i++)
f[i]=f[i-1]+f[i-m];
cout<<f[d]<<endl;
}
return 0;
}
反思:这些题找出递推式问题就解决了。
总结·:本次考试一般般,只要是递推不够好。