数据结构:组装齿轮问题

来源:互联网 发布:南方舆情数据研究院 编辑:程序博客网 时间:2024/04/28 22:22

题目:


背景

你的弟弟买了一套新的玩具,用这套玩具,他可以组装自己的机器。在玩具中有很多不同尺寸的齿轮,开始的时候他可以直接使用齿轮组装不同转速比

的传动装置,但后来他发现有些转速比用已有的齿轮就很难组装出来。他希望你给他编写一个电脑程序,帮助他找到组装传动装置的方法。

譬如,在这个玩具中包含了 6 齿、12 齿和 30 齿的齿轮,而你的弟弟希望搞一个转速比为 5:4 的传动装置。下图就显示了一种可能的方案:

齿轮

这个传动方案使用了四个齿轮,第一跟轴上是 30 齿和 12 齿的,第二跟轴上是 6 齿和 12 齿的。转速比可以通过如下公式获得:

(30 / 12) * (6 / 12) = (5 / 2) * (1 / 2) = 5 / 4 = 5:4

然而,使用以上三种齿轮,就没法组装出转速比为 1:6 的传动装置。

题目

给定齿轮的大小(齿轮有多少个齿),判断通过这些齿轮能否组成一定的转速比。我们假定每种齿轮的数量都足够多。

输入

输入的第一行是一个数字 n,它表示在玩具中有几种齿轮(1 <= n <= 20)。下一行包含了 n 个数字 c1...cn,以空白符隔开,他们表示了玩具中的

 n 种齿轮的大小(5 <= ci <= 100,其中 1 <= i <= n)。你可以假定在玩具中所有齿轮的大小都是最小齿轮大小的倍数。

再下一行有一个整数 m,它表示所需的实现的转速比有多少组,而之后的 m 行中每行都有两个整数 a 和 b,它们表示要实现的转速比为 a:b,其中

 1 <= a, b <= 10000。

 测试输入关于“测试输入”的帮助期待的输出关于“期待的输出”的帮助时间限制关于“时间限制”的帮助内存限制关于“内存限制”的帮助额外进程关于“{$a} 个额外进程”的帮助测试用例 1以文本方式显示
  1. 3↵
  2. 6 12 30↵
  3. 2↵
  4. 5 4↵
  5. 1 6↵
以文本方式显示
  1. Gear ratio 5:4 can be realized.↵
  2. Gear ratio 1:6 cannot be realized.↵
1秒1024KB0测试用例 2以文本方式显示
  1. 1↵
  2. 42↵
  3. 2↵
  4. 13 13↵
  5. 42 1↵
以文本方式显示
  1. Gear ratio 13:13 can be realized.↵
  2. Gear ratio 42:1 cannot be realized.↵
1秒1024KB0

思路:

这道题的本质其实是利用现有的齿轮齿数与最小齿数的比值,来作为因子,通过乘法或者除法,最后得到目标的比值的分子/分母。一般的做法就是把简化后的齿数相乘,通过大量的得到乘积,同时对目标比例的分子分母同时扩大n倍(分子分母扩大相同的倍数比值不变),测试扩大后的分子分母,是否在之前得到的乘积中出现过。
伪代码:
define num 100000

用每个数除以最小齿数(每个齿轮齿数都是最小齿数的整倍数),得到结果加到a[num]中,得到k个数。

同时用b[num]记录a[num]中出现的数。x出现过则b[x]置为1

//这一步可以先排序,再用后面的数除以第一个,也可以直接让每个数两两相除,如果余数是0而且商不为0,再加到a[num]中

for i 0到k // k是指当前a[num]中的数的个数,在下面的循环中也会改变k值

for j 0到k

if a[j]=0

continue //跳出这次循环,但是要继续

if a[i]%a[j]=0 //一开始我怀疑这个if 存在的意义,但是去掉这个if后最后一个用例无法通过

temp=a[i]/a[j]

if temp=0

continue //temp是0就没有意义了

if b[temp]不为1

temp加入a[num] //同时k++

b[temp]置为1

temp=a[i]*a[j] //temp如果是int型似乎会溢出

if temp>100000或者temp=0 //这个题目的测试用例是有限的,否则这个算法就是大失败

continue

else

if b[temp]不为1

temp加入a[num] //k++

b[temp]置为1

//完毕

看到上面的代码就是这个程序的核心部分——乘法。有了这个步骤以后,就可以在目标比例的分子分母中同时扩大n(n>1)倍时,测试在b[num]中是否为1(当然只要测试到100000)

代码:

#include <stdio.h>#include <math.h>#include <stdlib.h>#include <string.h>#define N 100000/*...........................算法分析:1、首先遍历所有齿轮,求出齿轮与最小齿轮之间的倍数,并用一个数组record记录是否出现过这个倍数2、倍数之间如果出现了新的倍数关系,加进去3、进行乘法关系,乘法得到的结果小于一给定值4、进行匹配,看分子分母是否出现过5、BIT的同学们请不要直接Copy代码,否则后果不堪设想~~~~.............................*/static unsigned long number[N];  //对倍数的储存int mark[N];   //记录是否出现过int cmp(const void *a,const void *b){return *(long *)a- *(long *)b;}void Init()  //初始化{int k=0;memset(number,0,sizeof(number));memset(mark,0,sizeof(mark));int n;  //齿轮static unsigned long temp[30];scanf("%d",&n);int i,j,min=50000;for(i=0;i<n;i++){scanf("%lu",&temp[i]);if(temp[i]<min) min=temp[i];   //找最小值}qsort(temp,n,sizeof(temp[0]),cmp);for(i=0;i<n;i++){int flag=temp[i]/min;number[k++]=flag;   //与最小倍数的关系mark[flag-1]=1;   //做了标记}for(i=0;i<k;i++){for(j=0;j<k;j++){if(number[j]==0) continue;if(number[i]%number[j]==0){unsigned long tep = number[i]/number[j];if(tep==0) continue;  //没有意义了if(mark[tep-1] != 1)  //增加新的倍数关系{number[k++] = tep;mark[tep-1]=1;}}unsigned long tep= number[i]*number[j];if(tep > N||tep == 0)  continue;//超出和为零没意义else{if(mark[tep-1]!=1){number[k++]=tep;mark[tep-1]=1;}}}}return;}long GCD(long a, long b)   //求最大公约数,化简,以免错过倍数{long temp;temp=a>b?a:b;b=a<b?a:b;a=temp;temp=a%b;while(temp){a=b;b=temp;temp=a%b;}return b;}int main(){freopen("C:\\Users\\Seayar\\Desktop\\input.txt","r",stdin);Init();int set;scanf("%d",&set);while(set--){long mya,myb,a,b,temp,tep_a,tep_b;scanf("%ld%ld",&mya,&myb);a=mya;b=myb;temp=GCD(a,b);a/=temp;b/=temp;long n=1;  //倍数扩大int flag=0;   //标记while(1){tep_a=a*n;tep_b=b*n;if(tep_a>N||tep_b>N) break;if(mark[tep_a-1]==1&&mark[tep_b-1]==1){flag=1;break;}n++;}if(flag==0)  printf("Gear ratio %ld:%ld cannot be realized.\n",mya,myb);  else  printf("Gear ratio %ld:%ld can be realized.\n",mya,myb);  }return 0;}




原创粉丝点击