免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3648 | 回复: 12
打印 上一主题 下一主题

[算法] 老大们,请教算法问题,很难 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-08-18 20:42 |只看该作者 |倒序浏览
[问题描述]
  有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若于张纸牌,然后移动。
  移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上;在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。
  现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。

  例如 N=4,4 堆纸牌数分别为:
  ① 9 ② 8 ③ 17 ④ 6
  移动3次可达到目的:
  从 ③ 取 4 张牌放到 ④ (9 8 13 10) ->; 从 ③ 取 3 张牌放到 ②(9 11 10 10)->; 从 ② 取 1 张牌放到①(10 10 10 10)。
[输 入]:
  键盘输入文件名。文件格式:
  N(N 堆纸牌,1 <= N <= 100)
  A1 A2 … An (N 堆纸牌,每堆纸牌初始数,l<= Ai <=10000)
[输 出]:
  输出至屏幕。格式为:
  所有堆均达到相等时的最少移动次数。‘
[输入输出样例]
a.in:
 4
 9 8 17 6

屏慕显示:
 3
    

论坛徽章:
0
2 [报告]
发表于 2003-08-18 21:13 |只看该作者

老大们,请教算法问题,很难


  1. 先计算总牌数total和平均数avg
  2. 用move(n)递归从An->;A1判断:
  3. An>;平均数,判断pai==0则把多余牌数移到A[n-1],移动次数+1,调用move(n-1)
  4.                pai>;0,比较多余牌数和pai,如果多余牌数<pai,则调用move(n-1)
  5.                                        如果多余牌数>;=pai,则移动pai张牌到A[n+1],移动次数+1,执行move(n+1)

  6. An=平均数,则判断n=1则返回,否则执行move(n-1)

  7. An<平均数则设一个变量pai保存离平均数所差的牌数,然后调用move(n-1)



  8. 不知道这个算法怎么样呀,写得有点乱,排版不好排
复制代码

论坛徽章:
0
3 [报告]
发表于 2003-08-18 21:28 |只看该作者

老大们,请教算法问题,很难

算法是写得出,可是怎么保证是最少解呢。。?

论坛徽章:
0
4 [报告]
发表于 2003-08-18 21:34 |只看该作者

老大们,请教算法问题,很难

我觉得只要在A1-An任何一个地方和相邻的牌不出现一次以上的移动,应该就是最少的了

论坛徽章:
0
5 [报告]
发表于 2003-08-19 05:56 |只看该作者

老大们,请教算法问题,很难

[quote]原帖由 "chenjn"]我觉得只要在A1-An任何一个地方和相邻的牌不出现一次以上的移动,应该就是最少的了[/quote 发表:
     

我觉得这道题,仔细分析一下,就比较简单了,而且感觉题目出的不够灵活,chenjin 的算法应该没有问题。
思路大致如下:
首先得满足其中一个边界,如 cards [0], 只能通过和右边的 cards [1] 交换牌数来实现,得到满足后,就不必理会 cards [0]了,边界自然就变成了cards [1], 问题的范围缩小,依此类推,很显然用递归算法是很容易实现的。

下面是自己编着玩的另外一种类似方法,同样是递归实现,刚开始学编程,多包含:

  1. /* 采用递归算法 */
  2. #include <stdlib.h>;
  3. #define HEAP 6         /* 堆数,自行修改 */
  4. #define AVERAGE 10      /* 平均每堆牌数 */
  5.                                                                                 
  6. int move( int [], int);
  7.                                                                                 
  8. int main()
  9. {
  10.         int cards [ HEAP ] = { 8, 9, 13, 6, 9, 15 };
  11.                                                                                 
  12.         int i;
  13.         printf ( "Before move:\n");
  14.         for ( i = 0; i <= HEAP -1; i++)
  15.                 printf ( "%d ", cards [i] );
  16.                                                                                 
  17.         printf ("\nMoving...\n");
  18.                                                                                 
  19.         printf ( "Move steps: %d\nAfter Move:\n\
  20. ", move ( cards, HEAP ));
  21.                                                                                 
  22.         for ( i = 0; i <= HEAP -1; i++)
  23.                 printf ( "%d ", cards[i]);
  24.         printf ("\n");
  25. }
  26.                                                                               
  27. int move ( int c [], int size)  /* 模拟传引用, 递数组和大小 */
  28. {
  29.         static count = 0;       /* 统计步数 */
  30.                                                                               
  31.         if ( size == 1 )
  32.                 return count;
  33.                                                                               
  34.         else {
  35.                 int n;
  36.                 n = size/2;     /* 把数组拆成两块,取前 n 堆牌 */
  37.                                                                               
  38.                 int i;
  39.                 int foresum = 0;
  40.                 for ( i = 0; i <= n-1; i++) /* 计算前 n 堆牌总数 */
  41.                         foresum += c[i];
  42.                                                                               
  43.                                                                               
  44.                 if ( foresum >; n * AVERAGE ) {
  45.                         c[n-1] -= foresum - n * AVERAGE;
  46.                         c[n] += foresum - n * AVERAGE;
  47.                         count += 1;
  48.                 }
  49.                                                                               
  50.                 else if ( foresum < n * AVERAGE ) {
  51.                         c[n-1] += n * AVERAGE - foresum;
  52.                         c[n] -= n * AVERAGE - foresum;
  53.                         count += 1;
  54.                 }
  55.                                                                               
  56.                 for ( i = 0; i <= HEAP -1; i++)
  57.                 /* 打印每次移动后结果, 这里感觉有问题,请指点 */
  58.                         printf ( "%d ", c[i]);
  59.                 printf ("\n");
  60.                                                                               
  61.                 move ( c, n ); /* 递归开始 */
  62.                 move ( &c[n], size - n );
  63.         }
  64.                                                                               
  65. }
复制代码

论坛徽章:
0
6 [报告]
发表于 2003-08-19 09:23 |只看该作者

老大们,请教算法问题,很难

想法很好.偶是想不出来

论坛徽章:
0
7 [报告]
发表于 2003-08-19 10:38 |只看该作者

老大们,请教算法问题,很难

这个算法不能保证最优

论坛徽章:
0
8 [报告]
发表于 2003-08-19 10:39 |只看该作者

老大们,请教算法问题,很难

说的详细些,把你的具体意见写出来大家一块讨论

论坛徽章:
0
9 [报告]
发表于 2003-08-20 17:48 |只看该作者

老大们,请教算法问题,很难

用A*算法搜索,启发函数设置为均方差。
每步都尽量让均方差降到最小。
kwx 该用户已被删除
10 [报告]
发表于 2003-08-21 16:21 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP