免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: linuxchyu
打印 上一主题 下一主题

[算法] 一道上海交大研究生入学考试试题:物以稀为贵 [复制链接]

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
21 [报告]
发表于 2013-03-14 14:04 |只看该作者
本帖最后由 cjaizss 于 2013-03-14 14:09 编辑

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int code_len = 8;//号码长度
  4. int neib[10][4];//邻接表
  5. int result[10][1000];//每个存储的如果是0,代表没被设置,否则result[i][j]存储的是以i打头j位号码有多少个


  6. void create_neib(void)
  7. {
  8.         int a[3][3];
  9.         int i,j;
  10.         int num,k;
  11.         for(i=0;i<3;i++)
  12.                 for(j=0;j<3;j++)
  13.                         a[i][j]=&a[i][j]-&a[0][0]+1;
  14.         for(i=0;i<3;i++)
  15.                 for(j=0;j<3;j++) {
  16.                         num = a[i][j];
  17.                         k=0;
  18.                         if(i-1>=0)
  19.                                 neib[num][k++] = a[i-1][j];
  20.                         if(i+1<3)
  21.                                 neib[num][k++] = a[i+1][j];
  22.                         if(j-1>=0)
  23.                                 neib[num][k++] = a[i][j-1];
  24.                         if(j+1<3)
  25.                                 neib[num][k++] = a[i][j+1];
  26.                         if(k<4)
  27.                                 neib[num][k] = -1;
  28.                 }
  29.         neib[0][0] = 8;
  30.         neib[0][1] = -1;
  31.         neib[8][3] = 0;

  32. }


  33. void cal_result_real(int start_num,int cnt)
  34. {
  35.         int i;
  36.         int r;
  37.         if(result[start_num][cnt])//因有这一步,降低时间复杂级别
  38.                 return;
  39.         if(cnt==1) {
  40.                 result[start_num][cnt] = 1;
  41.                 return;
  42.         }
  43.         r = 0;
  44.         for(i=0;i<4;i++)
  45.                 if(neib[start_num][i] >= 0) {
  46.                         cal_result_real(neib[start_num][i],cnt-1);
  47.                         r += result[neib[start_num][i]][cnt-1];
  48.                 } else
  49.                         break;
  50.         result[start_num][cnt] = r;


  51. }

  52. int cal_result(void)
  53. {
  54.         int i,j;
  55.         int ret;
  56.         for(i=0;i<10;i++)
  57.                 for(j=0;j<=code_len;j++)
  58.                         result[i][j]=0;

  59.         for(i=0;i<10;i++)//每个号码打头的都来一遍
  60.                 cal_result_real(i,code_len);
  61.         ret=0;
  62.         for(i=0;i<10;i++)
  63.                 ret+=result[i][code_len];
  64.         return ret;
  65. }

  66. int main(int argc,char**argv)
  67. {
  68.         int ret;

  69.         if(argc>1)
  70.                 code_len = atoi(argv[1]);
  71.         create_neib();
  72.         ret = cal_result();
  73.         printf("ret=%d\n",ret);
  74.         return 0;
  75. }
复制代码

论坛徽章:
0
22 [报告]
发表于 2013-03-14 15:54 |只看该作者
  1. (define ls
  2.   '((0 8)
  3.     (1 2 4)
  4.     (2 1 5 3)
  5.     (3 2 6)
  6.     (4 1 5 7)
  7.     (5 4 2 6 8)
  8.     (6 9 5 3)
  9.     (7 4 8)
  10.     (8 7 5 9 0)
  11.     (9 8 6)))

  12. (display
  13.   (let iter ((x 8) (c #f))
  14.     (if (zero? x) 1
  15.       (fold + 0
  16.             (map
  17.               (lambda (c) (iter (1- x) c))
  18.               (if c (assoc-ref ls c) (map car ls)))))))
复制代码

论坛徽章:
5
丑牛
日期:2014-01-21 08:26:26卯兔
日期:2014-03-11 06:37:43天秤座
日期:2014-03-25 08:52:52寅虎
日期:2014-04-19 11:39:48午马
日期:2014-08-06 03:56:58
23 [报告]
发表于 2013-03-14 17:31 |只看该作者
算了,难了点,,,

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-09-11 06:20:00
24 [报告]
发表于 2013-03-15 00:59 |只看该作者
回复 3# bruceteen


    嗯是的,只求有多少种方法就行了

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-09-11 06:20:00
25 [报告]
发表于 2013-03-15 01:01 |只看该作者
回复 9# cjaizss


   不用递归,只用DP就行了

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-09-11 06:20:00
26 [报告]
发表于 2013-03-15 01:12 |只看该作者
回复 22# hbmhalley


    Lisp果然强大,不知运行结果和时间是多少?

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-09-11 06:20:00
27 [报告]
发表于 2013-03-15 01:14 |只看该作者
回复 20# bruceteen


    嗯。结果对了,看看能不能再改进下算法?

论坛徽章:
0
28 [报告]
发表于 2013-03-17 16:45 |只看该作者
本帖最后由 leeXsen 于 2013-03-25 19:51 编辑
  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. #define mem_test(x) if ((x) == NULL) { \
  4.                         puts("Memory error!"); \
  5.                         exit(1); \
  6.                     }

  7. typedef struct tree {
  8.         int max;
  9.         int value;
  10.         struct tree **child;
  11. } Tree;

  12. static Tree t[10];
  13. static unsigned int sum = 0;

  14. static const int map[10][5] = {
  15.         {8, -1, -1, -1, 1},                /* 0 */
  16.         {2, 4, -1, -1, 2},                /* 1 */
  17.         {1, 3, 5, -1, 3},                        /* 2 */
  18.         {2, 6, -1, -1, 2},                /* 3 */
  19.         {1, 5, 7, -1, 3},                        /* 4 */
  20.         {2, 4, 6, 8, 4},                        /* 5 */
  21.         {3, 5, 9, -1, 3},                        /* 6 */
  22.         {4, 8, -1, -1, 2},                /* 7 */
  23.         {0, 5, 7, 9, 4},                        /* 8 */
  24.         {6, 8, -1, -1, 2}                        /* 9 */
  25. };

  26. void tree(Tree *p)
  27. {
  28.         int i;
  29.         int value;
  30.         static int layer = 0;

  31.         if (++layer < 8) {
  32.                 value = p->value;
  33.                 p->max = map[value][4];
  34.                 p->child = (Tree **)malloc(p->max * sizeof(Tree *));
  35.                 mem_test(p->child);

  36.                 for (i = 0; i < p->max; i++) {
  37.                         p->child[i] = (Tree *)malloc(sizeof(Tree));                       
  38.                         mem_test(p->child[i]);
  39.                         p->child[i]->value = map[value][i];
  40.                         tree(p->child[i]);
  41.                 }
  42.         }

  43.         --layer;
  44. }

  45. void init_tree(void)
  46. {
  47.         int i;

  48.         for (i = 0; i < 10; i++) {
  49.                 t[i].value = i;
  50.                 tree(&t[i]);
  51.         }
  52. }

  53. void show_tree(Tree *p)
  54. {
  55.         int i;
  56.         static int layer = 0;
  57.        
  58.         if (++layer < 9) {
  59.                 if (layer != 8) {
  60.                         for (i = 0; i < p->max; i++)
  61.                                 show_tree(p->child[i]);
  62.                 } else
  63.                         ++sum;
  64.         }

  65.         --layer;
  66. }

  67. void show()
  68. {
  69.         int i;

  70.         for (i = 0; i < 10; i++)
  71.                 show_tree(&t[i]);
  72. }       

  73. void main(void)
  74. {
  75.         init_tree();
  76.         show();
  77.         printf("%d\n", sum);
  78. }
复制代码
用递归简单点吧,我的好像有点长...

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
29 [报告]
发表于 2013-03-17 17:23 |只看该作者
话说这种题目需要数据结构和算法么= =
  1. local trans = {
  2.     [0] = { 8 },
  3.     [1] = { 2, 4 },
  4.     [2] = { 1, 3, 5 },
  5.     [3] = { 2, 6 },
  6.     [4] = { 1, 5, 7 },
  7.     [5] = { 2, 4, 6, 8 },
  8.     [6] = { 3, 5, 9 },
  9.     [7] = { 4, 8 },
  10.     [8] = { 0, 5, 7, 9 },
  11.     [9] = { 6, 8 },
  12. }

  13. local function search(n, idx)
  14.     idx = idx or 0
  15.     local count = 0
  16.     for _, v in ipairs(trans[n]) do
  17.         count = count + (idx == 6 and 1 or search(v, idx + 1))
  18.     end
  19.     return count
  20. end

  21. local count = 0
  22. for i = 0, 9 do
  23.     count = count + search(i)
  24. end
  25. print(count)
复制代码
还有,对于指定了规模的题目而言,是无法说复杂度的,复杂度在【输入】发生变化时才有效果,这题没输入。

论坛徽章:
0
30 [报告]
发表于 2013-03-17 20:26 |只看该作者
动态规划的代码复杂度是O(N),其中N为号码的长度
其实用矩阵乘法更快点,初始矩阵rela[j]表示用1步从i到j的可能情况数(初始是1),最后就是先求矩阵的7次方,然后对res[j]求和就行了,一次矩阵乘法的计算次数是10^3=1000次乘法,矩阵乘法用优化算法是log(N-1)次,所以计算次数大概是1000log(N-1)+100(100是对res[j]求和),也就是说,复杂度大概是O(logN),代码如下,结果求出是14826:
  1. #include <stdio.h>
  2. #include <string.h>

  3. int rela[10][10] = {{0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
  4.         {0, 0, 1, 0, 1, 0, 0, 0, 0, 0},
  5.         {0, 1, 0, 1, 0, 1, 0, 0, 0, 0},
  6.         {0, 0, 1, 0, 0, 0, 1, 0, 0, 0},
  7.         {0, 1, 0, 0, 0, 1, 0, 1, 0, 0},
  8.         {0, 0, 1, 0, 1, 0, 1, 0, 1, 0},
  9.         {0, 0, 0, 1, 0, 1, 0, 0, 0, 1},
  10.         {0, 0, 0, 0, 1, 0, 0, 0, 1, 0},
  11.         {1, 0, 0, 0, 0, 1, 0, 1, 0, 1},
  12.         {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}};
  13. int res[10][10], len = 7, i, j, ans;

  14. void
  15. mult(int s[][10], int t[][10]) {
  16.         int temp[10][10], i, j, k;

  17.         for (i = 0; i < 10; ++i)
  18.                 for (j = 0; j < 10; ++j) {
  19.                         temp[i][j] = 0;
  20.                         for (k = 0; k < 10; ++k)
  21.                                 temp[i][j] += s[i][k] * t[k][j];
  22.                 }
  23.         memcpy(s, temp, sizeof(temp));
  24. }

  25. int
  26. main()
  27. {
  28.         for (i = 0; i < 10; ++i)
  29.                 res[i][i] = 1;
  30.         for (i = 1; ; ) {
  31.                 if (len & i)
  32.                         mult(res, rela);
  33.                 if ((i <<= 1) > len)
  34.                         break;
  35.                 else
  36.                         mult(rela, rela);
  37.         }
  38.         for (i = ans = 0; i < 10; ++i)
  39.                 for (j = 0; j < 10; ++j)
  40.                         ans += res[i][j];
  41.         fprintf(stdout, "%d\n", ans);
  42.         return 0;
  43. }
复制代码
相比起动态规划,我认为矩阵乘法是最优的了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP