南海中学2017创新班考试总结

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;
}

  反思:这些题找出递推式问题就解决了。


    总结·:本次考试一般般,只要是递推不够好。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值