题目:
背景
你的弟弟买了一套新的玩具,用这套玩具,他可以组装自己的机器。在玩具中有很多不同尺寸的齿轮,开始的时候他可以直接使用齿轮组装不同转速比
的传动装置,但后来他发现有些转速比用已有的齿轮就很难组装出来。他希望你给他编写一个电脑程序,帮助他找到组装传动装置的方法。
譬如,在这个玩具中包含了 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。
测试输入 | 期待的输出 | 时间限制 | 内存限制 | 额外进程 | |
---|---|---|---|---|---|
测试用例 1 | 以文本方式显示
| 以文本方式显示
| 1秒 | 1024KB | 0 |
测试用例 2 | 以文本方式显示
| 以文本方式显示
| 1秒 | 1024KB | 0 |
思路:
这道题的本质其实是利用现有的齿轮齿数与最小齿数的比值,来作为因子,通过乘法或者除法,最后得到目标的比值的分子/分母。一般的做法就是把简化后的齿数相乘,通过大量的得到乘积,同时对目标比例的分子分母同时扩大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)
用每个数除以最小齿数(每个齿轮齿数都是最小齿数的整倍数),得到结果加到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;
}