看一下算法问题,很难!!

Delphist 2003-08-18 08:49:05
[问题描述]
  有 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
...全文
44 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
tianxueer 2003-08-19
  • 打赏
  • 举报
回复
对了,可能是我弄错了,对不起.我也找你的思路写了一个.
//--------------------------------------------------
#include <iostream.h>
#pragma hdrstop
#define n 5
#pragma argsused
int main(int argc, char* argv[])
{
int a[n];
int b=0;
for (int i=0;i<n;i++)
{
cin >>a[i];
b+=a[i];
}
int c=b/n;
int setp=0;
for (int i=0;i<n-1;i++)
{
if (a[i]==c)
continue;
if (a[i]>c)
{
a[i+1]+=c-a[i];
a[i]=c;
setp++;
}
if (a[i]<c)
{
a[i+1]-=c-a[i];
a[i]=c;
setp++;
}
}

cout <<setp;
getchar();
return 0;
}
//---------------------
顺便问一句,你是怎么有了这个思路的?
西江残月 2003-08-19
  • 打赏
  • 举报
回复
tianxueer(甜雪儿) 你说我说的不对啊!呵呵。。。

我的也是3次啊!

GoldenSea(void*) 的思路. 例如: 5个数: 5 9 12 6 3
第一次: 7 7 12 6 3
第二次: 7 7 7 11 3
第三次: 7 7 7 7 7

没错啊!你试试我调试过的程序:
这回绝对正确!我试了了n次了!累。。。

#include <stdio.h>
const MAXN = 100;
int i,n,step;
long av;
int work[MAXN+1];
int main(void)
{
scanf("%d",&n);
av=0;
for(i=1;i<=n;i++)
{
scanf("%d",&work[i]);
av+=work[i];
}
av/=i-1;
work[0]=0;
for(i=1;i<=n;i++)
{
if(work[0]!=0)step++;
work[i]+=work[0];
work[0]=work[i]-av;
}
printf("%d\n",step);
return 0;
}



西江残月 2003-08-19
  • 打赏
  • 举报
回复
刚才没调试有错误,sorry。
头文件还用#include <stdio.h>

av/=i;改为av/i-1; 这个没看出来,失败啊!
tianxueer 2003-08-19
  • 打赏
  • 举报
回复
1.景乐的还是有毛病. 设n=7. 7个数依次设为: 7 7 7 7 7 6 8 .只要一次就可(把8移一个给6).可是景乐的程序显示6次.

2. GoldenSea(void*) 的思路错误. 例如: 5个数: 5 9 12 6 3
第一次: 7 7 12 6 3
第二次: 7 7 7 11 3
第三次: 7 7 7 7 7
而 按照GoldenSea(void*)的思路要显示4次 .
GoldenSea(void*) 的思路任何数都能算的出来,但却是最麻烦的.
3.我只设个菜鸟.刚刚晕晕乎乎的学完了指针,连对象,类.都不知道是什么玩艺.如果说错了话,还请大家原谅,指教.
我怎么没思路呢? 是不是要学什么数据结构,离散数学什么的??
tonybaobao 2003-08-19
  • 打赏
  • 举报
回复
以下程序经过VS.net编译通过。

#include "stdafx.h"
using namespace std;

void Move(int* p,int num, int amount,int& move);

void main()
{
int num=0;
int index=0;
int amount=0;
int number_of_move=0;
int *p;
cout<<"Please input the number of heap:";
cin>>num;
while ( num<=0 )
{
cout<<"Input Error! Please input it again.\n"
<<"Please input the number of heap:";
cin>>num;
}
p=new int[num];
cout<<"Please input how many cards in each heap. The amounts should be Ns.\n";
loop:while ( index<num )
{
cin>>*(p+index);
amount+=*(p+index);
index++;
}
if ( amount%num )
{
cout<<"Input Error! Please input it again.\n";
amount=0;
index=0;
goto loop;
}
cout<<"There are "<<num<<" heaps.\n"<<"Cards' number in each heap is:\n";
for(index=0;index<num;index++)
cout<<*(p+index)<<' ';
cout<<"\nAfter moving the cards, each heap should have "<<amount/num<<" cards.\n";
Move(p,num,amount,number_of_move);
cout<<"The number of move is:"<<number_of_move<<endl;
}

void Move(int* p,int num, int amount,int& move)
{
int aver=amount/num;
int i=0;
while ( i<num )
{
int temp=0;
temp=*(p+i)-aver;
if( temp )
{
move++;
*(p+i)=aver;
i++;
*(p+i)+=temp;
}
else
i++;
}
}

小弟是新手,看上面的老大们都编写的那么短小精悍,真是有点惭愧。不过至少我还是去努力过了,请大家指正。谢谢:)
西江残月 2003-08-19
  • 打赏
  • 举报
回复
#include <iostream.h>
const MAXN = 100;
int i,n,step;
long av;
int work[MAXN+1];
int main(void)
{
scanf("%d",&n);
av=0;
for(i=1;i<=n;i++)
{
scanf("%d",&work[i]);
av+=work[i];
}
av/=i;
work[0]=0;
for(i=1;i<=n;i++)
{
if(work[0]!=0)step++;
work[i]+=work[0];
work[0]-=work[i]-av;
}
printf("%d\n",step);
return 0;
}

这样岂不清晰明了!
kbsoft 2003-08-19
  • 打赏
  • 举报
回复
楼上的,你的这种担心很没必要.在哪都是这两种情况都是一样的.
while(work[i]==0) i++;这不操作就是过滤移牌过程中产生的0
而work[i]第i堆牌移走后都会变为0
Delphist 2003-08-19
  • 打赏
  • 举报
回复
数是对了,但是要是1,1,1,19就会出现负数
kbsoft 2003-08-19
  • 打赏
  • 举报
回复
TO GoldenSea(void*)
我并不是按你的方法来做的,你看看符合么?!
kbsoft 2003-08-19
  • 打赏
  • 举报
回复
笔误我的程序是av/=n;
kbsoft 2003-08-19
  • 打赏
  • 举报
回复
FT,这么道题以为能赚100分了,没想到这么多人来令分:(
shiningpolarstar 2003-08-18
  • 打赏
  • 举报
回复
这个问题比较好解决,它只是一个特殊情况,kbsoft(景乐)的程序是面向的数据不一样的情况,所以只要数据不一样,那么它的步骤必然是最少的,所以只要在上边加一个小检验程序,如果数据一样,则输出0,否则按程序走。还有一个问题就是在
while(i<j)
{
work[i+1]+=work[i];
work[i]=0;
step++;
i++;
while(work[i]==0) i++;
}
这段程序中,如果i=1时,work[i]正好等于0,那么step已经加1了,为了避免这种情况的发生,我建议将step++;放到while(work[i]==0) i++;之后。
kbsoft 2003-08-18
  • 打赏
  • 举报
回复
FT!
如果每堆纸牌的数目都一样还移动什么.
tianxueer 2003-08-18
  • 打赏
  • 举报
回复
kbsoft(景乐) 的答案有问题.输入: n=5. 五个数都设为5. 试一下.其他还有很多.
kbsoft 2003-08-18
  • 打赏
  • 举报
回复
Dev-C++编译通过
kbsoft 2003-08-18
  • 打赏
  • 举报
回复
#include <stdio.h>
#define MAXN 100
int i,j,n,step;
long av;
int work[MAXN+1];
int main(void)
{
scanf("%d",&n);
av=0;
for(i=1;i<=n;i++)
{
scanf("%d",&work[i]);
av+=work[i];
}
av/=i;
for(i=1;i<=n;i++) work[i]-=av;
i=1,j=n;
while(work[i]==0) i++;
while(work[j]==0) j--;
while(i<j)
{
work[i+1]+=work[i];
work[i]=0;
step++;
i++;
while(work[i]==0) i++;
}
printf("%d\n",step);
return 0;
}
bm1408 2003-08-18
  • 打赏
  • 举报
回复
你们太聪明了!

ZhangYv(闭关修炼中...) 高二就编出来了!
太NB了!
看来真要改行了!
西江残月 2003-08-18
  • 打赏
  • 举报
回复
刚想了一下,原来不难的啊!大家分析一下我的算法对吗?

由于最后每一堆的牌要一样多,每一堆最后的牌数就是确定的了。
这是我们只需从第一张到最后一张一一分析就可以了!
比如9(a) 8(b) 17(c) 6(d)
a少1张就从b移1张过来
10(a) 7(b) 17(c) 6(d)
b少3张就从c移3张过来
10(a) 10(b) 14(c) 6(d)
c多4张就把多的移到d
10(a) 10(b) 10(c) 10(d)

这样做肯定是最少步骤的,原因就是牌只能往相邻的堆上移!(大家想一想是不是这样1)

在举一例证明一下:

start...7(a) 6(b) 1(c) 5(d) 6(e)
1.......5(a) 8(b) 1(c) 5(d) 6(e)
2.......5(a) 5(b) 4(c) 5(d) 6(e)
3.......5(a) 5(b) 5(c) 4(d) 6(e)
4.......5(a) 5(b) 5(c) 5(d) 5(e)

4步
是最少吧!

思路有了编程自然简单!大家自己练手吧!
Delphist 2003-08-18
  • 打赏
  • 举报
回复
是去年的,
现在都难倒程序员了
ZhangYv 2003-08-18
  • 打赏
  • 举报
回复
我记得前4年,我读高二上的时候就做出来了 :)
加载更多回复(2)

69,364

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧