usaco training 4.2.4 Cowcycles 题解

时间:2023-03-09 05:10:48
usaco training 4.2.4 Cowcycles 题解

Cowcycles题解

Originally by Don Gillies

[International readers should note that some words are puns on cows.]

Having made a fortune on Playbov magazine, Hugh Heifer has moved from his original field in the country to a fashionable yard in the suburbs. To visit fond pastoral memories, he wishes to cowmmute back to his old
stomping grounds. Being environmentally minded, Hugh wishes to transport himself using his own power on a Cowcycle (a bicycle specially fitted for his neatly manicured hooves).

Hugh weighs over a ton; as such, getting smoothly up to speed on traditional cowcycle gear sets is a bit challenging. Changing among some of the widely spaced gear ratios causes exertion that's hard on Hugh's heart.

Help Hugh outfit his Cowcycle by choosing F (1 <= F <= 5) gears (sprockets) in the front and R (1 <= R <= 10) gears in the rear of his F*R speed cowcycle subject to these rules:

  • The possible sizes (number of teeth) for the F front gears are specified.
  • The possible sizes (number of teeth) for the R rear gears are specified.
  • At any given gear setting, the gear ratio is the quotient of the number of teeth on the front gear and the number of teeth on the rear gear (i.e., number of front gear teeth divided by number of rear gear teeth)
  • The largest gear ratio must be at least three times the smallest.
  • The variance (see below) of the set of DIFFERENCES between successive (i.e., after sorting) gear ratios should be minimized.

Calculate the mean and variance of a set of differences (xi in this formula) by the following formulae:

usaco training 4.2.4 Cowcycles 题解

Deduce and print the optimal sets of F front gears and R rear gears so that the variance is minimized (and the ratios span a factor of at least 3x).

PROGRAM NAME: cowcycle

INPUT FORMAT

The first line contains F and R, the numbers of front and rear gears. The second line contains four numbers: F1, F2 (25 <= F1 < F2 <= 80), R1, and R2 (5 <= R1 < R2 <= 40). All front gears from F1 through F2 are
available; all rear gears from R1 through R2 are available. There will exist at least one legal set of gears.

SAMPLE INPUT (file cowcycle.in)

2 5
39 62 12 28

OUTPUT FORMAT

Display the number of teeth on the set of F chosen front gears, from smallest to largest, on the first line of output (separated by spaces). Display the number of teeth on the set of R chosen rear gears, from smallest
to largest, on the second line of output. All gears have an integer number of teeth, of course.

If multiple optimal answers exist, output the answer with the smallest front gear set (smallest first gear, or smallest second gear if first gears match, etc.). Likewise, if all first gears match, output the answer
with the smallest rear gear set (similar rules to the front gear set).

SAMPLE OUTPUT (file cowcycle.out)

39 53
12 13 15 23 27

Comment

The challenge in this problem is "reading the problem". Don't read further if you are working on that level of challenge. If the problem is just completely unclear to you, read in.

The problem wants you to find "an optimal set of gear ratios" such that the spacing between the ratios is most uniform. Consider the test case above:

2 5
39 62 12 28

This specifies two front gears from the set 39..62; five rear gears from the set 12..28. The program must examine all possible pairs of 62-39+1=24 front gears and all possible quintuples from 28-12+1=17 rear
gears. Combinatorically, The total number of possibilities is (24 take 2) times (17 take 5), which is 24!/22!/2! x 17!/5!/12! which is 656,880 possibilities (I think).

For each of these possibilities, calculations like the following. This example considers in some sense the "first" case: front gears of 39 and 40, rear gears of 12, 13, 14, 15, and 16.

First, calculate all the possible ratios:

39/12 = 3.25000000000000000000
39/13 = 3.00000000000000000000
39/14 = 2.78571428571428571428
39/15 = 2.60000000000000000000
39/16 = 2.43750000000000000000
40/12 = 3.33333333333333333333
40/13 = 3.07692307692307692307
40/14 = 2.85714285714285714285
40/15 = 2.66666666666666666666
40/16 = 2.50000000000000000000

Then, sort them:

39/16 = 2.43750000000000000000
40/16 = 2.50000000000000000000
39/15 = 2.60000000000000000000
40/15 = 2.66666666666666666666
39/14 = 2.78571428571428571428
40/14 = 2.85714285714285714285
39/13 = 3.00000000000000000000
40/13 = 3.07692307692307692307
39/12 = 3.25000000000000000000
40/12 = 3.33333333333333333333

Then, calculate the absolute value of the differences:

2.43750000000000000000 - 2.50000000000000000000 = 0.06250000000000000000
2.50000000000000000000 - 2.60000000000000000000 = 0.10000000000000000000
2.60000000000000000000 - 2.66666666666666666666 = 0.06666666666666666666
2.66666666666666666666 - 2.78571428571428571428 = 0.11904761904761904762
2.78571428571428571428 - 2.85714285714285714285 = 0.07142857142857142857
2.85714285714285714285 - 3.00000000000000000000 = 0.14285714285714285715
3.00000000000000000000 - 3.07692307692307692307 = 0.07692307692307692307
3.07692307692307692307 - 3.25000000000000000000 = 0.17307692307692307693
3.25000000000000000000 - 3.33333333333333333333 = 0.08333333333333333333

Then, calculate the mean and variance of the set of numbers on the right, above. The mean is (I think): 0.0995370370370370370366666. The variance is approximately 0.00129798488416722.

Of course this set of gears is not valid, since it does not have a 3x span from highest gear to lowest.

Find the set of gears that minimizes the variance and has a 3x or greater span.

描述

秀·谢夫(小奶牛)在花花公子杂志上中了大奖,于是她从农村搬到了城郊的一座别墅中。可是她还常常怀念乡村的生活,总想回到原来的农村逛逛。为了环保,秀决定骑上为她量身定做的奶牛自行车(特殊的自行车,专门为牛蹄设计)。

秀大约有一吨重。同样的,秀在普通的奶牛自行车上,要想骑得平平稳稳,也不是一件容易的事。因此,调节奶牛自行车的变速器让秀心力憔悴。

帮助秀选择她的奶牛自行车前面 F (usaco training 4.2.4 Cowcycles 题解)个齿轮和后面 R (usaco training 4.2.4 Cowcycles 题解)个齿轮,使她的
F*R 奶牛自行车符合下面的标准:

  1. 前面齿轮的型号(齿的数量)必须在给定的范围内。
  2. 后面齿轮的型号(齿的数量)必须在给定的范围内。
  3. 在每一种齿轮组合中,传动比率就是前面齿轮的齿数除以后面齿轮的齿数所得的商。
  4. 最大的传动比率至少是最小的三倍。
  5. 齿轮组合的转动比率(已排好序)相邻两项的差的的方差(见下面的例子) 应该达到最小。

按照下面的公式计算平均数与方差(xi 代表数据) :

usaco training 4.2.4 Cowcycles 题解

usaco training 4.2.4 Cowcycles 题解

计算并确定最佳齿轮组合(其中 F 个前齿轮,R 个后齿轮),使方差最小。

[编辑]格式

PROGRAM NAME: cowcycle

INPUT FORMAT:

(file cowcycle.in)

第一行是 F 和 R,表示前齿轮和后齿轮的数量。

第二行包括 4 个数字:F1,F2(25 <= F1 < F2 <= 80),R1,R2(5 <= R1 < R2 <= 40)。从 F1 到 F2 型号的前齿轮都是可用的;从 R1 到 R2 型号的后齿轮都是可用的。至少会有一组合法的解。

OUTPUT FORMAT:

(file cowcycle.out)

在第一行从小到大输出前齿轮的型号,用空格分开。在第二行从小到大输出后齿轮的型号,同样用空格分开。当然,齿轮的齿数一定是整数。

如果有多个解,输出前齿轮齿数最小的那一个(第一个齿轮齿数最小的,若第一个齿轮齿数相等,输出第二个齿轮齿数最小的……依此类推)。如果所有的前齿轮齿数都相等,照着上面的办法处理后齿轮(其实就是把第一个,第二个……齿轮分别设为第一,第二……个关键字来排序)。

[编辑]SAMPLE
INPUT

2 5
39 62 12 28

[编辑]SAMPLE
OUTPUT

39 53
12 13 15 23 27

[编辑]Comment

注释

这个问题最大的挑战就是“读懂题目”。慢慢读,不要想一步登天。如果你读不懂题目,还是得一遍一遍的把它读进去。

问题要我们找出“最佳齿轮组合”,即传动比率最接*均数的组合。考虑下面的测试数据:

2 5
39 62 12 28

这意味着有 2 个前齿轮,型号范围在 39..62 ;5个后齿轮,型号范围在 12..28。程序必须检查所有前齿轮组成的有序对(共 62-39+1=24 种齿轮),和所有后齿轮组成的五元组(共 28-12+1=17 种齿轮)。根据组合数学原理,总共有 24!/22!/2! x 17!/5!/12! = 656,880 种可能(我是这么认为的)。

对于每一种可能,做下面的计算。举个例子来说,对于枚举到的第一种情况:前齿轮是 39 和 40,后齿轮是 12,13,14,15 和 16。

首先,计算所有可能的传动比率:

39/12 = 3.25000000000000000000
39/13 = 3.00000000000000000000
39/14 = 2.78571428571428571428
39/15 = 2.60000000000000000000
39/16 = 2.43750000000000000000
40/12 = 3.33333333333333333333
40/13 = 3.07692307692307692307
40/14 = 2.85714285714285714285
40/15 = 2.66666666666666666666
40/16 = 2.50000000000000000000

然后,对它们进行排序:

39/16 = 2.43750000000000000000
40/16 = 2.50000000000000000000
39/15 = 2.60000000000000000000
40/15 = 2.66666666666666666666
39/14 = 2.78571428571428571428
40/14 = 2.85714285714285714285
39/13 = 3.00000000000000000000
40/13 = 3.07692307692307692307
39/12 = 3.25000000000000000000
40/12 = 3.33333333333333333333

然后,计算差的绝对值:

2.43750000000000000000 - 2.50000000000000000000 = 0.06250000000000000000
2.50000000000000000000 - 2.60000000000000000000 = 0.10000000000000000000
2.60000000000000000000 - 2.66666666666666666666 = 0.06666666666666666666
2.66666666666666666666 - 2.78571428571428571428 = 0.11904761904761904762
2.78571428571428571428 - 2.85714285714285714285 = 0.07142857142857142857
2.85714285714285714285 - 3.00000000000000000000 = 0.14285714285714285715
3.00000000000000000000 - 3.07692307692307692307 = 0.07692307692307692307
3.07692307692307692307 - 3.25000000000000000000 = 0.17307692307692307693
3.25000000000000000000 - 3.33333333333333333333 = 0.08333333333333333333

然后计算平均数和方差。

平均数是(我是这么认为的)0.0995370370370370370366666.。方差大约是 0.00129798488416722。

当然这个例子是错误的,因为它的最大传动比率没有比最小传动比率大3倍。

找出一个组合,拥有最小的方差,同时最大传动比率至少是最小传动比率的3倍。

---------------------------------分割线--------------------------------------

这道题乍一看把我吓了一跳。根据极限数据:C(56,5)*C(36,10)=9.7*10^14。不算排序就已经严重超时了!但是我还是抱着做做看的思路,直接深搜枚举所有情况并记录。由于我对常数的管理,使搜索的效率大大提高。

剪枝和优化:①如果小于三倍就可以直接退出,没必要算下去了。公式原来是:a[f]/b[1]<3*a[1]/b[f],但是由于乘法比除法快很多,我们可以化成a[f]*b[f]<3*a[1]*b[1]。

②求方差时,因为排过序,不必像解释的那样取绝对值,而是大的减小的。

③省掉不必要的函数。我果断把搜完后判断的处理和后齿轮的枚举放在了一起(inline的别说)

④在枚举齿轮的时候,没有用那种flag数组的记录,而是直接加一个参数直接循环。

。代码:

/*
PROG:cowcycle
ID:juan1973
LANG:C++
*/
#include<stdio.h>
using namespace std;
int a[57],b[37],ansa[57],ansb[37],f,r,f1,r1,f2,r2,i,cnt;
double sum,tot,ans,c[2017],t;
void find_r(int k,int step)
{
  int i,j;
  if (step==r+1)
  {
    if (a[f]*b[r]<3*a[1]*b[1]) return;   //if (a[f]/b[1]<3*a[1]/b[r])
    cnt=0;
    sum=tot=0;
    for (i=1;i<=f;i++)
      for (j=1;j<=r;j++)
        c[++cnt]=double(a[i])/double(b[j]);
    for (i=1;i<cnt;i++)
      for (j=i+1;j<=cnt;j++)
        if (c[i]>c[j]) {t=c[i];c[i]=c[j];c[j]=t;}
    for (i=1;i<cnt;i++){c[i]=c[i+1]-c[i];sum+=c[i];}
    sum/=--cnt;
    for (i=1;i<=cnt;i++) tot+=(c[i]-sum)*(c[i]-sum);
    if (tot<ans)
      {
        ans=tot;
        for (i=1;i<=f;i++) ansa[i]=a[i];
        for (i=1;i<=r;i++) ansb[i]=b[i];
      }
    return;
  }
  for (i=k;i<=r2-r+step;i++)
  {
    b[step]=i;
    find_r(i+1,step+1);
  }
}
void find_f(int k,int step)
{
  if (step==f+1){find_r(r1,1);return;}
  for (int i=k;i<=f2-f+step;i++)
  {
    a[step]=i;
    find_f(i+1,step+1);
  }
}
int main()
{
  freopen("cowcycle.in","r",stdin);
  freopen("cowcycle.out","w",stdout);
  scanf("%ld%ld",&f,&r);
  scanf("%ld%ld%ld%ld",&f1,&f2,&r1,&r2);
  ans=99999999;
  find_f(f1,1);
  for (i=1;i<f;i++) printf("%ld ",ansa[i]);printf("%ld\n",ansa[f]);
  for (i=1;i<r;i++) printf("%ld ",ansb[i]);printf("%ld\n",ansb[r]);
  //scanf("%ld%ld",&f,&r);
  return 0;
}