有解决这个问题的算法嘛?

zhongshan99 2001-12-14 03:57:32
要素有N个int型数据的排列。排列的每一个要素的值。请描述使该排列中连接的1部分值的合计成为最大的C函数。但是,请尽量考虑采用效率高的十进制。
...全文
278 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2001-12-25
  • 打赏
  • 举报
回复
只有人云亦云的人,才会说落后的,没有什么会落后的。
chinalian 2001-12-24
  • 打赏
  • 举报
回复
zhongshan99:我有时用Delphi开发,有时也用其它的语言。
Delphi落后了吗?哈哈!
chinalian 2001-12-21
  • 打赏
  • 举报
回复
zhongshan99(咬过的苹果):
即使是还未UPDATE的程序,-9 to -1也不会出错的。
chinalian 2001-12-21
  • 打赏
  • 举报
回复
这是我自己想出来的算法,没有完全测试过。经过你我的共同努力,这下应该没有问题了。
(- +...+)或(- +...+ - ...-)的情况时,由于未进行过前端查找且首个是负数,所以有Bug.
chinalian 2001-12-21
  • 打赏
  • 举报
回复
zhongshan99(咬过的苹果):
为了解决(- +...+)或(- +...+ - ...-)的情况,应将未尾的
if first >= last then
begin
first := iFeaMax;
last := iFeaMax;
end;
改为->
if first >= last then
begin
first := iFeaMax;
last := iFeaMax;
end
else
begin
//解决(- +...+)或(- +...+ - ...-)的情况
if (first = low(X)) and (X[first] < 0) then first := low(X) + 1;
end;
wanbaocheng 2001-12-21
  • 打赏
  • 举报
回复
你们为何不学习C#(读作c sharp),那可是很好的开发工具,delphi都落后了
「已注销」 2001-12-21
  • 打赏
  • 举报
回复
连长,是我弄错了,你的程序没有错误的。
看pascal没有多久,总是忘记to an downto ,呵呵。
你是用delphi做开发的吗?
最近我也在改学这个,作为以后基于windows的主要开发工具了,
以后要向你请教着方面的事情喽。
wanbaocheng 2001-12-20
  • 打赏
  • 举报
回复
对你的问题我还是不大明白,最好能举一个实例(简单的例子),OK!
mathe 2001-12-20
  • 打赏
  • 举报
回复
怎么都这么复杂呀,S(0)=0.
记S(k)为前k个元素的和,即S(k)=S(k-1)+a(k),计算S(k) ,k=1,...,N需要O(N)的时间
现在就变成求i<j使得S(j)-S(i)最大。
记M(k)为min{S(0),S(1),...,S(k-1)},即M(k)=min{M(k-1),S(k-1)},
I(k)为S(i)==M(k)(0<=i<k)的i. 即I(k)=k-1如果M(k)=S(k-1)不然I(k)=I(k-1)
计算M(k),I(k),k=1,...,N也需要O(N)的时间。
Result=max{S(k)-M(k),k=1,2,...,N}也需要O(N)的时间
设S(u)-M(u)为Result,则从a[I(u)+1]到a[u]的和取最大。

Suppose Input in a[1..N]
S[0]=0;
for(i=1;i<=N;i++)S[i]=a[i]+S[i-1];
M[1]=S[0];I[1]=0;
for(i=2;i<=N;i++){
if(S[i-1]<=M[i-1]){
M[i]=S[i-1];
I[i]=i-1;
}else{
M[i]=M[i-1];
I[i]=I[i-1];
}
}
Result=S[1]-M[1];u=1;
for(i=2;i<=N;i++){
if(Result<S[i]-M[i]){
u=i;Result=S[i]-M[i];
}
}
printf("The max sum is %d, in a[%d..%d]\n",Result,I[u]+1,u);
「已注销」 2001-12-20
  • 打赏
  • 举报
回复
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <time.h>

struct max_result{
int max;
int start;
int end;
};

typedef struct max_result MAX_RESULT;

MAX_RESULT* getmaxresult(){
MAX_RESULT* pthis=NULL;
pthis=(MAX_RESULT*)malloc(sizeof(MAX_RESULT));
if(NULL==pthis){
printf("not enough memory.\n");
exit(0);
}
memset(pthis,0,sizeof(MAX_RESULT));
return pthis;
}

void releasemaxresult(MAX_RESULT* pthis){
free(pthis);
}

#define MAX_BUFFER 1024
int buffer[MAX_BUFFER];
int pos;
void readdata(char* filename){
FILE* in;
char buf[MAX_BUFFER];
in=fopen(filename,"r");
if(in==NULL){
printf("%s file not exists.",filename);
exit(0);
}
pos=0;
memset(buffer,0,sizeof(buffer));
while(!feof(in)){
fscanf(in,"%s",buf);
buffer[pos++]=atoi(buf);
}
fclose(in);
}

void process(char* len,char* filename){
FILE* out;
int l;
out=fopen(filename,"w");
if(out==NULL){
printf("%s file is using.\n",filename);
exit(0);
}
l=atoi(len);
srand((unsigned int)time(NULL));
while(l--){
fprintf(out,"%d\n",(rand()-RAND_MAX/2));
}
fclose(out);
}

int main(int argc, char* argv[])
{
int i,j,k;
MAX_RESULT *pmax,*ptmp;
if(argc==3){
process(argv[1],argv[2]);
}

if(argc!=2){
printf("usage:program input.\n");
printf("input:file name.");
exit(0);
}

readdata(argv[1]);
if(pos==0) exit(0);
pmax=getmaxresult();
ptmp=getmaxresult();
pmax->max=buffer[0];
pmax->start=0;
pmax->end=0;
for(i=0;i<pos;i++){
k=0;
k+=buffer[i];
ptmp->max=k;
ptmp->start=i;
ptmp->end=i;
for(j=i+1;j<pos;j++){
k+=buffer[j];
if(k>ptmp->max){
ptmp->max=k;
ptmp->end=j;
}
}
if(ptmp->max>pmax->max){
pmax->max=ptmp->max;
pmax->start=ptmp->start;
pmax->end=ptmp->end;
}
}
printf("max result:%d\n",pmax->max);
printf("start:%d\n",pmax->start+1);
printf("end:%d\n",pmax->end+1);
releasemaxresult(pmax);
releasemaxresult(ptmp);
return 0;
}

上面这个程序使用穷举的方法来实现的。
但是我想要一个效率很高的算法。
因为上面的程序时间复杂度很高,在测试数据数量很大的情况下,
需要的时间很长。

多谢连长的程序。看来我还是没有说清楚,就是负数的情况也要考虑呀。
如果整个数组都是负数呢,那么答案就应该是最大的那个负数的位置了。

我希望给出的能够是程序。因为数学的表达式我是看不大明白的。
我查过一些有关动态规划的知识,据说可以解决这个问题,但是复杂的数学表达式,
把我吓怕了,我觉得这个问题还是比较简单的,不用看那么多的知识吧,要不不知道什么时候才能做出来呢。
「已注销」 2001-12-20
  • 打赏
  • 举报
回复
mathe:是呀,你的程序我已经做过了,正确呀,已经给分了,这个问题我已经结了呀。
怎么联系你呀。以后想跟你多多学习的。
mathe 2001-12-20
  • 打赏
  • 举报
回复
看我的算法呀O(N)的时间,绝对没有错误。
「已注销」 2001-12-20
  • 打赏
  • 举报
回复
连长,还有问题。
如果是-9 to -1的话,那么返回来的
first=0,
last=8
应该是first=last=8呀。
「已注销」 2001-12-20
  • 打赏
  • 举报
回复
ok.问题都解决了。厉害。
chinalian 2001-12-20
  • 打赏
  • 举报
回复
zhongshan99(咬过的苹果):对不起,我没有考虑到全是正整数的情况。
修改过的程序附在后面。
另,返回的first是0,就表示是序列的第一个元素;是1,第二个元素。
程序的主要思路是:
从序列的两端进行最大和序列的查找;初始化前序列和FSum为0,后序列和LSum为0
###如果FSum < LSum, 则从前端查找确定序列的第一个元素;否则从后端查找确定序列的最后一个元素;
从前端查找时,
如果FSum < 0, 则丢弃已查找的序列,FSum = 0,First 为下个元素,继续查找;
如果元素为负and不是本次循环的第一次and不是FSum < 0后查找的第一次,则下次查找的元素FNext还是本次查找的元素,Reset FSum, 返回###比较Fsum, LSum
从后端查找相似。
procedure GetMaxSerial(const X: array of integer;var first, last: integer);
var
i: integer;
FSum, LSum: integer; //用于保存从列头和列尾查找的序列和的最大值
FNext, LNext: integer; // 列头和列尾下一个要查找的元素
FeaMax, iFeaMax: integer; //保存最大单个元素及其序号
begin
//最大和序列的第一个和最后一个元素初始化为序列的第一个和最后一个元素
first := low(X); last := high(X);
FNext := low(X); LNext := high(X);
FeaMax := X[low(X)]; iFeaMax := low(X);
FSum := 0; LSum := 0;
while (FNext < LNext) do
begin
if FSum < LSum then
//确定序列的第一个元素
begin
for i := FNext to high(X) do
begin
if X[i] > FeaMax then
begin
FeaMax := X[i];
iFeaMax := i;
end; //保存最大的元素

FSum := FSum + X[i];
if FSum < 0 then
begin
FSum := 0;
First := i + 1;
FNext := i + 1;
Continue;
end;
if (X[i] < 0) and (i <> FNext) then //不是本次循环的第一次且是负数
begin
LSum := LSum - X[i];
FNext := i;
break;
end;
FNext := i + 1;
end; //end of for i
if i > high(X) then FNext := high(X); //已经到达列尾
end
else
//确定序列的最后一个元素
begin
for i := LNext Downto low(X) do
begin
if X[i] > FeaMax then
begin
FeaMax := X[i];
iFeaMax := i;
end; //保存最大的元素

LSum := LSum + X[i];
if LSum < 0 then
begin
LSum := 0;
last := i - 1;
LNext := i - 1;
Continue;
end;
if (X[i] < 0) and (i <> LNext) then //不是本次循环的第一次且是负数
begin
LSum := LSum - X[i];
LNext := i;
break;
end;
end; //end of for i
if i < low(X) then LNext := low(x); //已经到达列首
end; //end of 确定序列的最后一个元素
end; //end of while

if first >= last then
begin
first := iFeaMax;
last := iFeaMax;
end;
end;

「已注销」 2001-12-20
  • 打赏
  • 举报
回复
我发帖子不多,刚刚看看只能加到194分了。
连长能说说你的思路嘛。简单一些就可以了。
「已注销」 2001-12-20
  • 打赏
  • 举报
回复
mathe您好。有联系的方式嘛?以后可能还有问题要请教的,请多多帮忙。
「已注销」 2001-12-20
  • 打赏
  • 举报
回复
var
ia:array[1..9] of Integer;
i,first,last:Integer;
begin
for i:=1 to 9 do
ia[i]:=i;
first:=last:=0;
GetMaxSerial(ia,first,last);
end;

写了一个简单的程序,测试了一下,连长的程序有问题,
这种情况下是死循环,应该是判断的地方还有问题,
请改正一下我在试试呀,因为我还不大理解你的思路。
chinalian 2001-12-20
  • 打赏
  • 举报
回复
我的算法只需对每个元素访问一次,效率已经很高了。
chinalian 2001-12-20
  • 打赏
  • 举报
回复
zhongshan99(咬过的苹果):如果整个数组都是负数呢,那么答案就应该是最大的那个负数的位置了。这种情况我已经考虑了。
代码最后部分:
if first >= last then
begin
first := iFeaMax; //iFeaMax就是最大整数的位置。
last := iFeaMax;
end;
加载更多回复(7)

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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