2016级新生周赛(四)题解

1.折点计数满足折点的条件:前一个点和后一个点都比该点大;前一个点和后一个点都比该点小唯一坑点:第一个点和最后一个点肯定不是折点。。(这里容易数组越界)#include"stdio.h"intmain(){  inta[1002],times=0,i,n;  scanf("%d",&n);  for(i=0;i<n;i++)    scanf("%d",&a[i]);  for(i=1;i<n-1;i++)  {    if(a[i]>a[i-1]&&a[i]>a[i+1]||a[i]<a[i-1]&&a[i]<a[i+1])    times++;  }  printf("%d\",times);  return0;} 2.疲惫的一天简单的思考题。。。。5种情况:1.先坐第一辆,再坐第二辆2.先坐第二辆,再坐第一辆3.只坐第一辆4.只坐第二辆5.两辆都不坐#include"stdio.h"#include"math.h"intmin(inta,intb){if(b-a>0)returna;returnb;}intmain(void){  intx1,y1,x2,y2,e,sum;  scanf("%d%d%d%d",&x1,&y1,&x2,&y2);  sum=1000;sum=min(sum,x1+abs(1000-y1));sum=min(sum,x2+abs(1000-y2));sum=min(sum,x1+abs(x2-y1)+abs(1000-y2));sum=min(sum,x2+abs(x1-y2)+abs(1000-y1));  printf("%d\",sum);  return0;}3.1的个数一道简单的进制转换题,不停的除2取余即可#include"stdio.h"int main(){inta,b=0,n;scanf("%d",&a);while(a--){b=0;scanf("%d",&n);while(n!=0){if(n%21)b+=1;n=n/2;if(n2){b+=1;break;}}  printf("%d\",b);}}      4.约瑟夫环约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。分析:(1)由于对于每个人只有死和活两种状态,因此可以用布朗型数组标记每个人的状态,可用true表示死,false表示活。(2)开始时每个人都是活的,所以数组初值全部赋为false。(3)模拟杀人过程,直到所有人都被杀死为止。无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。因此如果要追求效率,就要打破常规,实施一点数学策略。为了讨论方便,先把问题稍微改变一下,并不影响原意:问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。我们知道第一个人(编号一定是(m-1))出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=mmodn的人开始):kk+1k+2...n-2,n-1,0,1,2,...k-2并且从k开始报0。我们把他们的编号做一下转换:k-->0k+1-->1k+2-->2......k-2-->n-2变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x'=(x+k)modn如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的情况----这显然就是一个倒推问题!好了,思路出来了,下面写递推公式:令f表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]递推公式f[1]=0;f=(f+m)modi;(i>1)有了这个公式,我们要做的就是从1-n顺序算出f的数值,最后结果是f[n]。因为实际生活中编号总是从1开始,我们输出f[n]+1由于是逐级递推,不需要保存每个f,程序也是异常简单:#include"stdio.h"intmain(){intn,m,i,j,ans=0;scanf("%d%d",&n,&m);for(i=1;i<=n;i++)ans=(ans+m)%i;printf("%d\",ans+1);}(其实这道题暴力也能过。。。)5.Beru-taxi题意:给出cds家的坐标,和m个出租车的坐标以及速度,求出租车到cds家的最小时间题解:水题一个。。。其他点到Vasiliy的距离除以速度的最小值就是答案(锻炼一波小16们的翻译能力)代码:#include"stdio.h"#include"math.h"#definemaxn1005intmin(inta,intb){if(b-a>0)returna;returnb;}int main(){inti,j,n;doublea,b;doublex,y,z;doublet,mins=100000;scanf("%lf%lf",&a,&b);scanf("%d",&n);for(i=1;i<=n;i++){scanf("%lf%lf%lf",&x,&y,&z);t=sqrt((x-a)(x-a)+(y-b)(y-b))/z;mins=min(mins,t);} printf("%.4f\",mins);}6.零钱问题两种解法:解法一:枚举所有可能出现的情况当前花费金钱数小于50元时,肯定要找一张50元,同理找完50后剩下的钱也是这种找法。代码如下:#include"stdio.h"int main(){intt,a,b,c;scanf("%d",&t);a=100-t;c=a;b=0;if(a>=50){b+=1;a=a-50;}if(a>=10&&a<50){b+=a/10;a=a-a/10*10;}if(a>=5&&a<10){b+=1;a=a-5;}if(a>=2&&a<10){b+=a/2;a=a%2;}if(a==1) b+=1;printf("%d%d\",c,b);}解法二:将金钱问题转化成完全背包问题(小石榴们可以自学一发什么是背包问题,很实用)具体实现如下:#include"stdio.h"#include"string.h"intmin(inta,intb) {   returna>b?b:a; } intdp[110]; intmain() {   intn,m,k,i,j;   inta[6]={1,2,5,10,50};   while(scanf("%d",&n)!=EOF)   {     m=100-n;     memset(dp,0x3f3f3f,sizeof(dp));     dp[0]=0;     for(i=0;i<5;i++)     {       for(j=a[i];j<=m;j++)       {         dp[j]=min(dp[j],dp[j-a[i]]+1);       }     }     printf("%d%d\",m,dp[m]);   }   return0; } 

posted @ 2022-10-22 18:33  河南工业大学算法协会  阅读(9)  评论(0编辑  收藏  举报