找回密码
 欢迎注册
楼主: sw2wolf

[讨论] 高德纳书中一道很普通的题目

[复制链接]
发表于 2010-3-26 13:46:34 | 显示全部楼层
求最优解不难,一下四组皆可
1, 4, 5, 7, 8, 9, 12, 13, 15, 16, 20, 25, 27, 30, 31, 33, 37, 38, 41, 43,44, 46, 47, 48, 49
1, 5, 7, 8, 9, 12, 13, 15, 20, 25, 27, 30, 31, 33, 36, 37, 38, 41, 43, 44, 46, 47, 48, 49
1, 4, 7, 8, 9, 12, 13, 15, 16, 25, 27, 30, 31, 33, 37, 38, 41, 43, 44, 45, 46, 47, 48, 49
7, 8, 12, 13, 15, 16, 25, 27, 30, 31, 33, 36, 37, 38, 41, 43, 44, 45, 46,47, 48, 49
和为
119.5179003017603207542302960921700499402435778084733414943130797735074
所有和的一半为119.5179003017603922470202231131221884062508285908309350855973734662694
误差为$7.15*10^-14$

评分

参与人数 1威望 +2 金币 +2 收起 理由
wayne + 2 + 2 太强了,我跟您简直不是一个数量级!!!

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-26 15:10:12 | 显示全部楼层
mathe三十一层的解说明他计算力挺强。赫赫。
想不出比Fan三层给的算法更有效的了。
对于Fan所提到的分为两大组,可以优化一下,稍稍减少一些计算量:
因为根号下1-50中包括1-7这样的整数,也包括1-5倍根号2这样的数,所以可以把它们分在一起。
一组是根号下13,14,15,17,19,21,22,23,26,29,30,31,33,34,35,37,38,39,41,42,43,46,47;一共23个数,有2^22种组合,可以都算出来存在一个40M的文件中;
另一组是1-7,1-5倍根号2,1-4倍根号3,1-3倍根号5,1-2倍的根号6,7,10,11,29乘16乘11乘7乘4乘4乘4乘4大约9M多种组合。那就搜索这么多次吧。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-26 16:21:20 | 显示全部楼层
最优解是8组而不是4组,我前面漏了一半。
程序就是用Fans的方法,因为不不需要考虑10秒的限制。而且说实在,有这时间去做优化,这个慢的版本的程序的结果早就出来了
让程序继续搜索更大范围的解,可以得到更多一点的较优解:
delta=6.40363e-013:[ 1 2 3 4 6 7 9 10 12 14 15 16 20 21 23 24 26 29 35 37 38 41 42 43 44 45 47 ]
delta=6.40363e-013:[ 2 3 4 6 7 9 10 12 14 15 20 21 23 24 25 26 29 35 37 38 41 42 43 44 45 47 ]
delta=6.40363e-013:[ 1 2 3 6 7 10 12 14 15 16 20 21 23 24 25 26 29 35 37 38 41 42 43 44 45 47 ]
delta=6.40349e-013:[ 2 4 6 7 9 10 14 15 20 21 23 24 25 26 27 29 35 37 38 41 42 43 44 45 47 ]
delta=6.40349e-013:[ 1 2 6 7 10 14 15 16 20 21 23 24 25 26 27 29 35 37 38 41 42 43 44 45 47 ]
delta=6.40349e-013:[ 1 2 4 6 7 9 10 14 15 16 20 21 23 24 26 27 29 35 37 38 41 42 43 44 45 47 ]
delta=6.40363e-013:[ 2 3 6 7 10 12 14 15 16 20 21 23 24 26 29 35 36 37 38 41 42 43 44 45 47 ]
delta=6.40363e-013:[ 1 2 3 6 7 9 10 12 14 15 20 21 23 24 26 29 35 36 37 38 41 42 43 44 45 47 ]
delta=6.40349e-013:[ 2 6 7 10 14 15 16 20 21 23 24 26 27 29 35 36 37 38 41 42 43 44 45 47 ]
delta=6.40349e-013:[ 1 2 6 7 9 10 14 15 20 21 23 24 26 27 29 35 36 37 38 41 42 43 44 45 47 ]
delta=6.40363e-013:[ 2 3 6 7 9 10 12 14 15 20 21 23 24 26 29 35 37 38 41 42 43 44 45 47 49 ]
delta=6.40363e-013:[ 1 2 3 4 6 7 10 12 14 15 20 21 23 24 26 29 35 37 38 41 42 43 44 45 47 49 ]
delta=6.40349e-013:[ 2 6 7 9 10 14 15 20 21 23 24 26 27 29 35 37 38 41 42 43 44 45 47 49 ]
delta=6.40349e-013:[ 1 2 4 6 7 10 14 15 20 21 23 24 26 27 29 35 37 38 41 42 43 44 45 47 49 ]
推荐
delta=7.14984e-014:[ 1 4 5 7 8 9 12 13 15 16 20 25 27 30 31 33 37 38 41 43 44 46 47 48 49 ]
delta=7.14984e-014:[ 1 5 7 8 9 12 13 15 20 25 27 30 31 33 36 37 38 41 43 44 46 47 48 49 ]
delta=7.14984e-014:[ 4 5 7 8 9 12 13 15 16 20 27 30 31 33 36 37 38 41 43 44 46 47 48 49 ]
delta=7.14984e-014:[ 5 7 8 12 13 15 16 20 25 27 30 31 33 36 37 38 41 43 44 46 47 48 49 ]
delta=7.14845e-014:[ 1 4 7 8 9 12 13 15 16 25 27 30 31 33 37 38 41 43 44 45 46 47 48 49 ]
delta=7.14845e-014:[ 7 8 12 13 15 16 25 27 30 31 33 36 37 38 41 43 44 45 46 47 48 49 ]
delta=7.14845e-014:[ 4 7 8 9 12 13 15 16 27 30 31 33 36 37 38 41 43 44 45 46 47 48 49 ]
delta=7.14845e-014:[ 1 7 8 9 12 13 15 25 27 30 31 33 36 37 38 41 43 44 45 46 47 48 49 ]
delta=2.62609e-013:[ 1 3 8 9 11 14 16 17 18 20 21 24 25 26 28 31 32 33 36 38 39 41 42 47 50 ]
delta=2.72074e-013:[ 1 4 6 7 8 9 10 12 15 16 18 19 20 24 25 29 30 32 34 38 39 40 41 45 47 50 ]
delta=2.72074e-013:[ 4 6 7 8 9 10 12 15 16 18 19 20 24 29 30 32 34 36 38 39 40 41 45 47 50 ]
delta=2.72074e-013:[ 6 7 8 10 12 15 16 18 19 20 24 25 29 30 32 34 36 38 39 40 41 45 47 50 ]
delta=2.72074e-013:[ 1 6 7 8 9 10 12 15 18 19 20 24 25 29 30 32 34 36 38 39 40 41 45 47 50 ]
delta=2.62609e-013:[ 1 3 4 8 11 14 16 17 18 20 21 24 25 26 28 31 32 33 38 39 41 42 47 49 50 ]
delta=2.62609e-013:[ 3 8 9 11 14 16 17 18 20 21 24 25 26 28 31 32 33 38 39 41 42 47 49 50 ]
delta=2.62609e-013:[ 1 3 8 11 14 17 18 20 21 24 25 26 28 31 32 33 36 38 39 41 42 47 49 50 ]
delta=2.62609e-013:[ 3 4 8 11 14 16 17 18 20 21 24 26 28 31 32 33 36 38 39 41 42 47 49 50 ]
delta=2.62609e-013:[ 1 3 4 8 9 11 14 17 18 20 21 24 26 28 31 32 33 36 38 39 41 42 47 49 50 ]
delta=2.72074e-013:[ 1 4 6 7 8 10 12 15 18 19 20 24 25 29 30 32 34 38 39 40 41 45 47 49 50 ]
delta=2.72074e-013:[ 6 7 8 9 10 12 15 18 19 20 24 25 29 30 32 34 38 39 40 41 45 47 49 50 ]
delta=2.72074e-013:[ 1 6 7 8 9 10 12 15 16 18 19 20 24 29 30 32 34 38 39 40 41 45 47 49 50 ]
delta=2.72074e-013:[ 4 6 7 8 10 12 15 18 19 20 24 29 30 32 34 36 38 39 40 41 45 47 49 50 ][code]
// sumsqr.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <math.h>
#include <algorithm>
using namespace std;
#define N 50
#define M (N/2)
unsigned long long data[]={

评分

参与人数 1金币 +50 收起 理由
gxqcn + 50 最佳答案,及程序源码。

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-26 16:39:41 | 显示全部楼层
先贴出我的计算结果。

50个数的和是 239.0358006035207600

得到的1个数组是:[7,8,12,13,15,16,25,27,30,31,33,36,37,38,41,43,44,45,46,47,48,49]

这个数组的和是:119.5179003017603200

运行时间:31360 ms

主要的瓶颈是调用VC的快速排序很耗时。如果改用自己写的快速排序,速度可以更快些。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-26 16:41:57 | 显示全部楼层
本帖最后由 liangbch 于 2010-3-26 17:08 编辑

再贴出代码,主要算法思想 参考自 10楼。
在我的电脑上,总的运行时间大约31秒,其中快速排序时间18.5秒。

  1. #include "stdafx.h"
  2. #include "math.h"
  3. #include "stdlib.h"
  4. #include "search.h"
  5. #include "memory.h"
  6. #include "string.h"
  7. #include "windows.h"

  8. typedef unsigned long DWORD;
  9. #define MAX_N (50)

  10. #define TRUE 1
  11. #define FALSE 0


  12. typedef struct
  13. {
  14.         DWORD bitMap;
  15.         DWORD sum;
  16. }SQRT_SUM;


  17. typedef struct
  18. {
  19.         DWORD bitMap1;
  20.         DWORD bitMap2;
  21.         double sum;
  22. }SQRT_SUM_RST;


  23. double g_sqrt_arr[MAX_N];
  24. SQRT_SUM *pTab1=NULL;
  25. SQRT_SUM *pTab2=NULL;

  26. DWORD  mask_arr[]=
  27. {
  28.         1,                1<<1,        1<<2,        1<<3,        1<<4,
  29.         1<<5,        1<<6,        1<<7,        1<<8,        1<<9,
  30.         1<<10,        1<<11,        1<<12,        1<<13,        1<<14,
  31.         1<<15,        1<<16,        1<<17,        1<<18,        1<<19,
  32.         1<<20,        1<<21,        1<<22,        1<<23,        1<<24
  33. };

  34. double g_half_sum;


  35. int __cdecl ItemCmp( const void *element1, const void *element2 )
  36. {
  37.         SQRT_SUM *p1,*p2;
  38.         p1=(SQRT_SUM *)element1;
  39.         p2=(SQRT_SUM *)element2;
  40.        
  41.         if (p1->sum > p2->sum )
  42.                 return 1;
  43.         else if (p1->sum <p2->sum )
  44.                 return -1;
  45.         else
  46.                 return 0;
  47. }

  48.    
  49. int  InitData()
  50. {
  51.         DWORD i,j;
  52.         DWORD key,t;
  53.         double s=0.00;
  54.        
  55.         for ( i=0;i<MAX_N;i++)
  56.         {
  57.                 g_sqrt_arr[i]= sqrt((double)(i+1));
  58.                 s+=g_sqrt_arr[i];
  59.         }
  60.         printf("\nsum=%.16f\n",s);
  61.         g_half_sum =s * 0.5;
  62.        
  63.         pTab1=new SQRT_SUM[ 1<<25 ];
  64.         pTab2=new SQRT_SUM[ 1<<25 ];
  65.        
  66.         if ( pTab1==NULL ||  pTab2==NULL )
  67.         {
  68.                 printf("No memrory");
  69.                 return FALSE;
  70.         }
  71.         //---------------
  72.        
  73.         for (key=0; key < (1 << 25); key++)
  74.         {
  75.                
  76.                 for (s=0.00,j=0; j<25;j++)
  77.                 {
  78.                         if (key & mask_arr[j] )
  79.                         {
  80.                                 s+= g_sqrt_arr[j];
  81.                         }
  82.                 }
  83.                 pTab1[key].bitMap=key;
  84.                 pTab1[key].sum= (DWORD)(s* 8388608.00+0.5);
  85.         }

  86.         for (key=0; key < (1 << 25); key++)
  87.         {
  88.                
  89.                 s=0;
  90.                 for (j=0; j<25;j++)
  91.                 {
  92.                         if (key & mask_arr[j] )
  93.                         {
  94.                                 s+= g_sqrt_arr[j+25];
  95.                         }
  96.                 }
  97.                 pTab2[key].bitMap=key;
  98.                 pTab2[key].sum= (DWORD)(s* 8388608.00+0.5);
  99.         }
  100.         //----------------------------------
  101.         t=GetTickCount();
  102.         qsort( (void *)pTab1, (size_t)(1<<25), sizeof( SQRT_SUM), ItemCmp );
  103.         qsort( (void *)pTab2, (size_t)(1<<25), sizeof( SQRT_SUM), ItemCmp );
  104.         t=GetTickCount()-t;

  105.         printf("It take %d ms for sort 2 arrays\n",t);
  106.        
  107.         return TRUE;
  108. }

  109. void  unInitData()
  110. {
  111.         if ( pTab1 !=NULL)
  112.         {
  113.                 delete[] pTab1; pTab1=NULL;
  114.         }

  115.         if ( pTab2 !=NULL)
  116.         {
  117.                 delete[] pTab2; pTab2=NULL;
  118.         }
  119. }

  120. int binSearch( const SQRT_SUM* pTab, DWORD n, int end, int *pLow, int *pHigh)
  121. {
  122.         int low,high,mid;
  123.         //-----------------
  124.         low=0;
  125.         high=end;
  126.         while (1)
  127.         {
  128.                 if (high-low<=1)
  129.                 {
  130.                         break;
  131.                 }
  132.                 else
  133.                 {
  134.                         mid=(low+high)/2;
  135.                         if (n>=pTab[mid].sum)
  136.                                 low=mid;
  137.                         else
  138.                                 high=mid-1;
  139.                 }
  140.         }

  141.         if ( pTab[low].sum >= n-1)
  142.                 low--;
  143.         low++;
  144.         if ( pTab[high].sum <= n+1)
  145.                 high++;
  146.         high--;
  147.         *pLow=low;
  148.         *pHigh=high;
  149.         return (low<=high);
  150. }

  151. double getDouble( int tabNo, DWORD key)
  152. {
  153.         double r;
  154.         int i;

  155.         for (r=0.00,i=0;i<25;i++)
  156.         {
  157.                 if (key & mask_arr[i] )
  158.                 {
  159.                         if (tabNo==0)
  160.                                 r+= g_sqrt_arr[i];
  161.                         else
  162.                             r+= g_sqrt_arr[i+25];
  163.                 }
  164.         }
  165.         return r;
  166. }

  167. double printfArray(DWORD key1,DWORD key2)
  168. {
  169.         int i;
  170.         double s=0;
  171.        
  172.         printf("[");
  173.         for (i=0;i<25;i++)
  174.         {
  175.                 if (key1 & mask_arr[i] )
  176.                 {
  177.                         printf("%d,",i+1);
  178.                         s+= sqrt( (double)(i+1));
  179.                 }
  180.                
  181.         }
  182.         for (i=0;i<25;i++)
  183.         {
  184.                 if (key2 & mask_arr[i] )
  185.                 {
  186.                         printf("%d,",i+26);
  187.                         s+= sqrt( (double)(i+26));
  188.                 }
  189.                
  190.         }
  191.         printf("]");
  192.         return s;
  193. }

  194. void search(int lmt,int *pIdx1,int *pIdx2)
  195. {
  196.         int i,j,end;
  197.         double minDiff=1000000;
  198.         int idx1,idx2;
  199.        
  200.         end=(1<<25)-1;
  201.         for (i=0;i< (1<<25) ; i++)
  202.         {
  203.                 double f1,f2;
  204.                 DWORD n1;
  205.                 int high,low;

  206.                 n1= pTab1[i].sum;
  207.                 if ( binSearch(pTab2,lmt-n1,end,&low,&high) )
  208.                 {
  209.                         f1=getDouble( 0, pTab1[i].bitMap);

  210.                         for (j=low;j<=high;j++)
  211.                         {
  212.                                 f2=getDouble( 1, pTab2[j].bitMap);
  213.                                 if  ( fabs( f1+ f2 - g_half_sum)<minDiff)
  214.                                 {
  215.                                         minDiff=fabs( f1+ f2 - g_half_sum);
  216.                                         idx1=i;
  217.                                         idx2=j;
  218.                                 }
  219.                                
  220.                         }
  221.                         if (high<end)
  222.                                 end=high;
  223.                 }
  224.         }
  225.         *pIdx1=idx1;
  226.         *pIdx2=idx2;
  227. }

  228. int main(int argc, char* argv[])
  229. {
  230.         double s;
  231.         DWORD t1,t2,lmt;
  232.         int idx1,idx2;
  233.        
  234.         t1=GetTickCount();
  235.         InitData();
  236.         lmt= (DWORD)(g_half_sum *  8388608.00+0.5);
  237.        
  238.         search(lmt,&idx1,&idx2);
  239.         printf("\narray1 is:\n");
  240.         s=printfArray(pTab1[idx1].bitMap,pTab2[idx2].bitMap);
  241.         printf("\nThe sum is %.16f\n",s);

  242.         unInitData();
  243.         t2=GetTickCount()-t1;
  244.         printf("\nIt take %u ms\n",t2);

  245.         return 0;
  246. }

  247. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-26 20:43:00 | 显示全部楼层
嗯,先给出我的答案吧:
方案是
1 4 7 8 9 12 13 15 16 25 27 30 31 33 37 38 41 43 44 45 46 47 48 49
2 3 5 6 10 11 14 17 18 19 20 21 22 23 24 26 28 29 32 34 35 36 39 40 42 50
两组之和的差为1.43e-13。

程序运行时间约11秒。(由于机器是前年的笔记本,在台式机上开一些编译优化什么的应该可以期待跑在10s以内……)

大致算法:

将50个数分为两组,每组25个,分别记为组A和组B。然后分别将组A和组B的所有数字组合(都是2^25种)枚举、排序,存入两个数组list1和list2。然后从上到下枚举list1中的所有元素,从list2中找到一个元素,使得两者的和在不超过sum的一半的情况下最大。因为本题相当于使得小的那部分尽量大,因此这样就可以求出最佳解。

时间复杂度分析:
枚举数字组合中,首先,初始数组中只有一个元素0。然后循环执行如下步骤,将所有的元素添加入数组:(假设当前待添加的元素是x)
将数组复制一份,其中一份不变,另一份每个元素+x。然后归并排序。
这样复杂度就是O(2^25)的了。

枚举list1时,以一个指针x表示x从list1的第一个元素枚举到最后一个元素;以一个指针y表示对应于当前的x,满足条件的最大的元素的位置。不难发现当x单调递增时y一定是单调递减的。因此复杂度也是O(2^25)。

空间复杂度分析:
归并排序时,以一个数组list1记录当前的数字组合,然后准备一个数组L来表示复制出的另一份数字组合,归并时从后往前在list1中填入数字。这样就可以充分利用list1中的空间,同时保证不会出现冲突的情况。这样,以list1和list2记录两串元素,分别为2^25,然后以L记录复制出的数字串,为2^24。总使用空间约640MB。这样机器会稍微卡一点,但还是可以接受的。

程序清单:(我的代码风格不太好,窘……)
  1. #include <stdio.h>
  2. #include <iostream>

  3. using namespace std;

  4. const int MaxN = 1 << 25;

  5. int n, i, j, k, x, y;
  6. int out[60]; // 记录输出方案,其中out[x]==1表示方案中元素x属于少的那部分
  7. unsigned long long sum, ans, ans_x, ans_y; // ans记录少的那半的总和,ans_x记录右半边元素的和,ans_y记录左半边元素的和
  8. unsigned long long a[60]; // 记录输入的50个元素
  9. unsigned long long list1[MaxN], list2[MaxN], L[MaxN >> 1]; // 含义如上所述

  10. void make(int st, int ed) // 构造2^25的有序数列
  11. {
  12.     int i, j, k, x, y;
  13.    
  14.     list1[0] = 0;
  15.     for (i=st; i<ed; i++)
  16.     {
  17.         for (j=0; j<(1<<(i-st)); j++) L[j] = list1[j] + a[i];
  18.         x = y = (1 << (i - st)) - 1;
  19.         for (k=(1<<(i-st+1))-1; k>=0; k--)
  20.         {
  21.             if (x>=0 && (y<0 || list1[x]>L[y])) { list1[k] = list1[x]; x --; }
  22.             else { list1[k] = L[y]; y --; }
  23.         }   
  24.     }   
  25. }   

  26. bool check(int st, int ed, unsigned long long S, int mask) // 检查相应的方案mask是否可以得到和S
  27. {
  28.     int i;
  29.    
  30.     for (i=st; i<ed; i++) if (mask & (1 << (i - st))) S -= a[i];
  31.     if (!S)
  32.     {
  33.         for (i=st; i<ed; i++) if (mask & (1 << (i - st))) out[i] = 1;
  34.         return 1;
  35.     } else return 0;
  36. }   

  37. int main()
  38. {
  39.     freopen("1.in", "r", stdin);
  40.     scanf("%d", &n);
  41.     for (i=0; i<n; i++) // 输入
  42.     {
  43.         cin >> a[i];
  44.         sum += a[i];
  45.     }   
  46.    
  47.     make(0, n / 2); // 构造前半
  48.     for (i=0; i<(1<<(n/2)); i++) list2[i] = list1[i]; // 存入list2中
  49.     make(n / 2, n); // 构造后半,此时前半在list2,后半在list1
  50.     y = (1 << (n / 2)) - 1; // list2中的指针
  51.     for (x=0; x<(1<<(n/2)); x++) // list1中的指针
  52.     {
  53.         while (y && list1[x]+list2[y]>sum/2) y --; // 找到最大的满足条件的y
  54.         if (list1[x]+list2[y]>ans && list1[x]+list2[y]<=sum/2) // 若满足条件且大于当前解则更新
  55.         {
  56.             ans = list1[x] + list2[y];
  57.             ans_x = list1[x];
  58.             ans_y = list2[y];
  59.         }   
  60.     }   
  61.     freopen("1.out", "w", stdout); // 输出
  62.     for (i=0; i<(1<<(n/2)); i++) if (check(0, n / 2, ans_y, i)) break;
  63.     for (i=0; i<(1<<(n/2)); i++) if (check(n / 2, n, ans_x, i)) break;
  64.     for (i=0; i<n; i++) if (out[i]) printf("%d ", i + 1); printf("\n");
  65.     for (i=0; i<n; i++) if (!out[i]) printf("%d ", i + 1); printf("\n");
  66.     cout << ans << " " << sum - ans - ans << endl;
  67. }
复制代码
输入数据:(这些数据是相应的实数乘以2^56取整的结果,Fans友情提供)
50
72057594037927936
101904826760412361
124807413944863399
144115188075855872
161125678563890424
176504337485538768
190646473898007863
203809653520824722
216172782113783808
227866119871621714
238988002719557251
249614827889726798
259807350090317420
269614829005170980
279077861676669750
288230376151711744
297101071346254269
305714480281237083
314091770526006817
322251357127780848
330209379075203405
337980074690455987
345576080981165471
353008674971077535
360287970189639680
367423078101941656
374422241834590198
381292947796015726
388042019499834581
394675696941228988
401199704155648221
407619307041649444
413939363109682179
420164364493449324
426298475306584890
432345564227567616
438309233037348441
444192841707656799
449999530536264313
455732239743243429
461393726875353099
466986582310951157
472513243112822805
477976005439114502
483377035691671273
488718380555307200
494001976059951504
499229655779453597
504403158265495552
509524133802061805
   
输出数据:
1 4 7 8 9 12 13 15 16 25 27 30 31 33 37 38 41 43 44 45 46 47 48 49
2 3 5 6 10 11 14 17 18 19 20 21 22 23 24 26 28 29 32 34 35 36 39 40 42 50
8612172340209789951 10302


个人感想:
本题是KeyTo9_Fans大牛丢给他的手下Fans_Fans的。按照Fans大牛的说法,这是一道水题,咱不屑于切,杀鸡焉用牛刀,看你那么久没来逛论坛了,就交给你了吧!其实Fans大牛也是苦思冥想了半天的,嗯,这里Fans_Fans小朋友就不揭穿他了
Fans大牛的形象是光辉的!伟大的!这种题对于他来说不过是小菜一碟!(嘛,反正事实大家都清楚 Fans大牛典型的想法灰常好代码灰常那个的,反正手下嘛,用来堆代码做苦力的,有Fans_Fans在就不用亲自披挂上阵了,多好

最后插一个小花絮……Fans大牛以为Fans_Fans不打算写,在楼上先开始写了,结果还是被Fans_Fans抢先写完喽~

Fans_Fans现在不知道该说啥,又急着打游戏去,所以说的挺没逻辑的,窘……反正中心思想是:代码是Fans_Fans的,想法是Fans的,嗯。

另外Fans还有一些改进,不过这些就交给Fans说明了,Fans_Fans就不越俎代庖了,嗯。

(话说不知道Fans是啥想法,看到Fans_Fans在这里这么说居然兴奋的红光满面OTL)

评分

参与人数 1金币 +3 收起 理由
gxqcn + 3 片子好,花絮也够吸引人。

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-26 21:01:01 | 显示全部楼层
表格显然是抄我的
这个题目的确有点水,不过要限定时间还是有点繁琐的.
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-26 21:05:53 | 显示全部楼层
36#的make函数还是比较巧妙的。我直接构造所有数据然后sort都不只10秒
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-26 21:38:48 | 显示全部楼层
没有抄。

我是用Windows计算器一个一个按出来的。

没想到按出来的结果居然和mathe大师的表格一字不差。

嗯,Fans的想法基本上都实现了。

制作列表,扫描列表都是$O(n)$的。

只可惜没有足够的内存保存各个数值对应的选数方案。

所以不得不先把最优结果算出来,然后调用了$2^25$次check过程,逐一检查到底是哪种选数方案得到这样的结果。

而check过程里面还有一层循环。

这使得逐一检查方案的时间复杂度为$O(n*log(n))$。

所幸的是,这部分操作的常数因子比快速排序的常数因子小,所以总的运行时间少了。

要继续改进的话,得把$32#$中zgg___的精神付诸实现。

只有充分领会了zgg___的精神,才能真正实现$O(n)$制表、$O(n)$扫表、$O(n)$出方案的美好愿望。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-26 21:41:49 | 显示全部楼层
上面过程还有唯一的问题是没有进行误差分析(不过这个属于鸡蛋里面挑骨头了)。
还有36#充分体现了ACMer们分工合作,各司其职的重要性(如同男耕女织一样)
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-5-5 19:39 , Processed in 0.206203 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表