在C#版发一个石子合并问题,看看大家对这类问题的一般思路是什么!

绿色夹克衫 2011-04-20 12:01:56
加精
这是一个小问题,不算难,却有不少大牛甚至大师都研究过这个问题

n堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。试设计一个算法,计算出将n堆石子合并成一堆的最小代价。

举个例子,比如: 1 2 3 4,有不少合并方法,比如

1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)

括号里面为总代价

可以看出,第一种方法的代价最低,现在随便给出n堆石子,用程序算出这个最小合并代价
...全文
3669 188 打赏 收藏 转发到动态 举报
写回复
用AI写文章
188 条回复
切换为时间正序
请发表友善的回复…
发表回复
绿色夹克衫 2011-05-11
  • 打赏
  • 举报
回复
构造了一个反例,32, 1, 1, 4, 1, 4, 1, 1, 32,用你的贪心方法算的话是166,实际上最优是157

[Quote=引用 186 楼 aliezeng77 的回复:]

应该是贪心算法吧,不过涉及到大整数计算时速度很慢
[/Quote]
绿色夹克衫 2011-05-10
  • 打赏
  • 举报
回复
从中间来的思路应该说也有人提到过,不过你加上了向左右移动,我认为这还不能保证结果的正确,因为在移动的过程中并不一定只有一个极点,也许存在先增再降的情况,不过小型的反例不太好找。

[Quote=引用 185 楼 aliezeng77 的回复:]
思路是:
1. 输入每堆石子数并保存在数组A中,将从第0堆到第i堆的石子总数保存在数组SUM的第i个元素中。
2. 设函数stone(int start, int end)返回合并从start到end堆的最小代价,则stone(start, end)=min({stone(start, i)+stone(i+1, end)|i=start,start+1,...,end-1})+SUM(st……
[/Quote]
aliezeng77 2011-05-10
  • 打赏
  • 举报
回复
应该是贪心算法吧,不过涉及到大整数计算时速度很慢
aliezeng77 2011-05-10
  • 打赏
  • 举报
回复
思路是:
1. 输入每堆石子数并保存在数组A中,将从第0堆到第i堆的石子总数保存在数组SUM的第i个元素中。
2. 设函数stone(int start, int end)返回合并从start到end堆的最小代价,则stone(start, end)=min({stone(start, i)+stone(i+1, end)|i=start,start+1,...,end-1})+SUM(start,end);
SUM(start, end)=第start堆石子到第end堆石子的总石子数目;
3. 设splt=min(abs(SUM(start, i)-SUM(i+1, end))| i=start,start+1,...,end-1),称splt为
为SUM(start, end)中分,记做splt=split(start, end);通过观察可知使stone(start, end)=stone(start, i)+stone(i+1, end)+SUM(start,end)成立的i应该在splt附近(未严格证明,应该可证);
4. 先令min=stone(start, splt)+stone(splt+1,end),再令i=splt-1向start移动计算
left=stone(start, i)+stone(i+1,end),如果left=<min则令min=left,i=i-1重新计算left,直到left>min;类似地令i=splt+1向end移动计算right=stone(start, i)+stone(i+1,end),如果right=<min则令min=right,i=i-1重新计算right,直到right>min;
5. 为了避免重复计算stone(start, end),每次计算后将计算结果保存到Rslts中,每次计算前先检索计算结果,如果检索到结果就直接返回,否则按照4条中方法进行计算;因为内存限制,不能保存所有计算结果,所以Rslts[0]中保存end-start<=RESULT_LEN的计算结果,Rslts[1]中保存end-start>RESULT_LEN的计算结果,Rslts[0]中最多保存CLEAR_COUNT-1个计算结果,当Rslts[0]中计算结果达到CLEAR_COUNT时则清除Rslts[0]保存的所有结果,以避免虚拟内存不够。
绿色夹克衫 2011-05-10
  • 打赏
  • 举报
回复
to:aliezeng77

还没有测试你的程序的结果是否正确,你先说一下思路吧,看起来效率应该是不错的,我上面的C#程序跑500万规模的大概要200多秒。Cpu:Intel® Pentium® Processor E2160 (1M Cache, 1.80 GHz, 800 MHz FSB),内存是4G
aliezeng77 2011-05-09
  • 打赏
  • 举报
回复
#include <stdio.h>
#include <windows.h>
#include <winbase.h>

#define ITYPE _int64
#define STONE_SIZE 5000000 //问题规模
#define RESULT_LEN 100 //
#define CLEAR_COUNT 5000000 //

typedef struct tagResult RSLT;
typedef RSLT* PRSLT;
struct tagResult{ //保存调用结果stone(start, end)的结构体
ITYPE result; //保存stone调用返回值
int end; //对应end
PRSLT next; //指向下一个调用结果
};

typedef struct tagResults RSLTS;
struct tagResults{
int Count; //合并结果数量
PRSLT Result[STONE_SIZE]; //Result[n]保存stone(n, end)的合并结果
};

RSLTS Rslts[2]; //Rslts[0]保存{stone(start, end)| end-start<=RESULT_LEN};Rslts[1]保存{stone(start, end)| end-start>RESULT_LEN}
PRSLT garbage=NULL; //Result回收站,保存

PRSLT getResult();
void ClearGarbage();

int A[STONE_SIZE]; //石堆数组
ITYPE SUM[STONE_SIZE]; //SUM[n]保存A中第0到第n个元素之和

void initResults();
void ClearResults();
ITYPE getResults(int start, int end);
void insertResults(int start, int end, ITYPE result);
void freeResults();

ITYPE stone(int start, int end);
int input();
int split(int start, int end);
void calSum(int a[], int count);


void main()
{
int cnt;
unsigned long tick;

initResults();
garbage=NULL;

while(1){
cnt=input();
tick=GetTickCount();
calSum(A, cnt);
printf("stone:%I64u\n\n", stone(0, cnt-1));
printf("use time %d minseconds.\n", GetTickCount()-tick);

ClearResults();
ClearGarbage();
}
}

ITYPE stone(int start, int end)
{
int i, splt;
ITYPE sum, min,left, right;

if(end-start==0) return 0;
else if(end-start==1) return A[start]+A[end];
else{
left=getResults(start, end);
if(left>0) return left;
}

if(start==0){
sum=SUM[end];
}
else{
sum=SUM[end]-SUM[start-1];
}

splt=split(start, end);

if(splt<end){
min=stone(start,splt)+ stone(splt+1,end);
}
else{
min=0x0FFFFFFFFFFFFFFF;
}

i=splt;

while(start<i)
{
left=stone(start, i-1)+ stone(i, end);

if(left>min){
break;
}
min=left;
i--;
}

i=splt;
while(i+2<=end){
right=stone(start, i+1)+ stone(i+2, end);

if(right>min){
break;
}
min=right;
i++;
}

min=min+sum;
insertResults(start, end, min);
return min;
}

//计算数组和
void calSum(int a[], int count)
{
int i;

SUM[0]=A[0];
for(i=1; i<count; i++){
SUM[i]=SUM[i-1]+A[i];
}
}

//二分查找中值位置
int split(int start, int end)
{
ITYPE sum, half, preSum;
int i=start, j=end, k=(i+j)/2;

if(start==0){
preSum=0;
}
else{
preSum=SUM[start-1];
}

sum=SUM[end]-preSum;
half=preSum+sum/2;


while(i+1<j){
if(half<SUM[k]){
j=k;
k=(i+j)/2;
}
else if(SUM[k]<half){
i=k;
k=(i+j)/2;
}
else if(half==SUM[k]){
return k;
}
}

if(SUM[i]+SUM[j]<sum+2*preSum){
return j;
}
else if(SUM[i]+SUM[j]>sum+2*preSum){
return i;
}
else if(A[i]<A[j]){
return j;
}
else{
return i;
}
}

void initResults()
{
int i, j;

for(i=0; i<2; i++){
Rslts[i].Count=0;

for(j=0; j<STONE_SIZE; j++){
Rslts[i].Result[j]=NULL;
}
}
}

void ClearResults()
{
int i, j;
PRSLT p, q;

for(i=0; i<2; i++){
Rslts[i].Count=0;

for(j=0; j<STONE_SIZE; j++){
p=Rslts[i].Result[j];
Rslts[i].Result[j]=NULL;

while(p!=NULL){
q=p->next;
free(p);
p=q;
}
}
}
}

ITYPE getResults(int start, int end)
{
PRSLT p;

if(end-start>RESULT_LEN){
p=Rslts[1].Result[start];
}
else{
p=Rslts[0].Result[start];
}

while(p){
if(p->end==end){
return p->result;
}

p=p->next;
}

return 0;
}

void insertResults(int start, int end, ITYPE result)
{
PRSLT p=getResult();

if(end-start>RESULT_LEN){//插入Rslts[1]
p->end=end;
p->result=result;
p->next=Rslts[1].Result[start];
Rslts[1].Result[start]=p;

Rslts[1].Count++;
if(Rslts[1].Count%1000000==0){
printf("Rslts[1].Count=%d\n", Rslts[1].Count);
}
}
else{ //插入Rslts[1]
p->end=end;
p->result=result;
p->next=Rslts[0].Result[start];
Rslts[0].Result[start]=p;

Rslts[0].Count++;
if(Rslts[0].Count%1000000==0){
printf("Results %d...\n", Rslts[0].Count);
}

if(Rslts[0].Count>CLEAR_COUNT){
printf("freeResults...\n");
freeResults();
}
}
}

//输入N个整数
int input()
{
int i, cnt, flag;

printf("请输入石子堆数:");
scanf("%d", &cnt);
printf("\n");

printf("生成每堆石子数目(0/1/2=手动/随机/顺序):");
scanf("%d", &flag);

if(flag==0){
printf("请输入每堆石子个数:\n");
for(i=0; i<cnt; i++){
printf("第%d堆:", i+1);
scanf("%d", &A[i]);
}
}
else if(flag==1){
srand(GetTickCount());

for(i=0; i<cnt; i++){
A[i]=rand()%100+1;
}
}
else{
for(i=0; i<cnt; i++) A[i]=i+1;

}
printf("\n");

return cnt;
}

void freeResults()
{
int i;
PRSLT pTail;

Rslts[0].Count=0;

for(i=0; i<STONE_SIZE; i++){
if(Rslts[0].Result[i]){
pTail=Rslts[0].Result[i];

while(pTail->next){
pTail=pTail->next;
}

pTail->next=garbage;
garbage=Rslts[0].Result[i];
Rslts[0].Result[i]=NULL;
}
}
}

PRSLT getResult()
{
PRSLT p;

if(garbage){
p=garbage;
garbage=garbage->next;
}
else{
p=malloc(sizeof(RSLT));
}

return p;
}

void ClearGarbage()
{
PRSLT p, q;

p=garbage;
garbage=NULL;

while(p){
q=p->next;
free(p);
p=q;
}
}
aliezeng77 2011-05-06
  • 打赏
  • 举报
回复
优化了下,现在算150万规模的耗时180秒,还可继续优化
aliezeng77 2011-05-06
  • 打赏
  • 举报
回复
优化了下,现在算500万规模的耗时373875minseconds,发现2G DDR太小了!
aliezeng77 2011-05-05
  • 打赏
  • 举报
回复
贴出代码如下:

VS6.0 编译通过

#include <stdio.h>
#include <windows.h>
#include <winbase.h>

typedef struct tagResult RSLT;
typedef RSLT* PRSLT;

struct tagResult{
_int64 result;
int end;

PRSLT next;
};

#define SIZE 500000
int A[SIZE];
_int64 SUM[SIZE];
PRSLT Results[SIZE];

void initResults();
void ClearResults();
_int64 getResults(int start, int end);
void insertResult(int start, int end, _int64 result);

_int64 stone(int start, int end);

int split(int start, int end);
void calSum(int a[], int count);

int input();


void main()
{
int cnt;
unsigned long tick;

initResults();
while(1)
{
cnt=input();
tick=GetTickCount();
calSum(A, cnt);
printf("stone:%I64u\n\n", stone(0, cnt-1));
printf("use time %d minseconds.\n", GetTickCount()-tick);
ClearResults();
}
}



_int64 stone(int start, int end)
{
int i, splt;
_int64 sum, min,left, right;

if(end-start==0) return 0;
else if(end-start==1) return A[start]+A[end];
else{
left=getResults(start, end);
if(left>0) return left;
}

if(start==0)
{
sum=SUM[end];
}
else{
sum=SUM[end]-SUM[start-1];
}

splt=split(start, end);

if(splt<end)
{
min=stone(start,splt)+ stone(splt+1,end);
}
else
min=0x0FFFFFFFFFFFFFFF;

i=splt;

while(start<i)
{
left=stone(start, i-1)+ stone(i, end);

if(left>min)
{
break;
}
min=left;
i--;
}

i=splt;
while(i+2<=end)
{
right=stone(start, i+1)+ stone(i+2, end);

if(right>min){
break;
}
min=right;
i++;
}

insertResult(start, end, min+sum);
return min+sum;
}

//计算数组和
void calSum(int a[], int count)
{
int i;

SUM[0]=A[0];
for(i=1; i<count; i++)
{
SUM[i]=SUM[i-1]+A[i];
}
}

//二分查找中值位置
int split(int start, int end)
{
_int64 sum, half, preSum;
int i=start, j=end, k=(i+j)/2;

if(start==0)
{
preSum=0;
}
else
{
preSum=SUM[start-1];
}

sum=SUM[end]-preSum;
half=preSum+sum/2;


while(i+1<j)
{
if(half<SUM[k])
{
j=k;
k=(i+j)/2;
}
else if(SUM[k]<half)
{
i=k;
k=(i+j)/2;
}
else if(half==SUM[k])
{
return k;
}
}

if(SUM[i]+SUM[j]<sum+2*preSum)
{
return j;
}
else if(SUM[i]+SUM[j]>sum+2*preSum)
{
return i;
}
else if(A[i]<A[j])
{
return j;
}
else
{
return i;
}
}

void initResults()
{
int i;

for(i=0; i<SIZE; i++)
{
Results[i]=NULL;
}
}

void ClearResults()
{
int i;
PRSLT p, q;

for(i=0; i<SIZE; i++)
{
p=Results[i];
Results[i]=NULL;

while(p!=NULL)
{
q=p->next;
free(p);
p=q;
}
}
}

_int64 getResults(int start, int end)
{
PRSLT p=Results[start];

while(p!=NULL)
{
if(p->end==end)
{
return p->result;
}

p=p->next;
}

return 0;
}

void insertResult(int start, int end, _int64 result)
{
PRSLT p=malloc(sizeof(RSLT));

p->end=end;
p->result=result;
p->next=Results[start];
Results[start]=p;
}

//输入N个整数
int input()
{
int i, cnt, flag;

printf("请输入石子堆数:");
scanf("%d", &cnt);
printf("\n");

printf("生成每堆石子数目(0/1/2=手动/随机/顺序):");
scanf("%d", &flag);

if(flag==0)
{
printf("请输入每堆石子个数:\n");
for(i=0; i<cnt; i++)
{
printf("第%d堆:", i+1);
scanf("%d", &A[i]);
}
}
else if(flag==1)
{
srand(GetTickCount());

for(i=0; i<cnt; i++)
{
A[i]=rand()%100+1;
}
}
else
{
for(i=0; i<cnt; i++) A[i]=i+1;

}
printf("\n");

return cnt;
}
aliezeng77 2011-05-05
  • 打赏
  • 举报
回复
计算60万堆数据耗时17.5s
计算70万堆数据耗时23.8s
计算80万堆数据耗时49.9s

计算90万堆数据虚拟内存不够,直接崩溃!
我的机器是Intel Core2 Duo CPU,主频2.99GHz,2G DDR

aliezeng77 2011-05-05
  • 打赏
  • 举报
回复
在随机生成的每堆石子数不大于100的情况下我的程序优化后500000堆15秒内解决!
blacksapper 2011-05-04
  • 打赏
  • 举报
回复
这个无非是先动小数字,既然是小数字就用霍夫曼算法咯,求最小权值
躺着的树懒 2011-05-03
  • 打赏
  • 举报
回复
霍夫曼树哈
zywkeven 2011-05-03
  • 打赏
  • 举报
回复
算法问题,个人没办法想出最优算法,因为首先要证明你的算法是正确的,所以只用了穷举法,PHP代码的.主要思想是要把每一次合并的位置列举出来,
举个例子:1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24);其表示操作的数组应该是Array(1,1,0);
表示:
第一次合并第1项与第2项,
第二次合并第1项与第2项,
第三次合并第0项与第1项,
代码:

function sand($ary){

$size = sizeof($ary);

$order_ary = Array();

$end_ary = Array();

for($i = 0;$i < $size-1 ;$i ++){

//将$order_ary初始化为array(0,0,...);

$order_ary[$i] = 0;

$end_ary[$i] = $size - $i- 2;

}

$not_finish = true;

$counter_begin = 0;

$min_result = 0;

$min_array = Array();

while ($not_finish){

$total_times = 0;

$result = 0;

$ary_new = $ary;

while ($total_times < $size-1){

$local_result = $ary_new[($order_ary[$total_times])] + $ary_new[($order_ary[$total_times])+1];

$result += $local_result;

for($i = 0 ;$i< sizeof($ary_new); $i ++) {

if ($i == ($order_ary[$total_times])) {

$ary_new[$i] = $local_result;


} else if($i > ($order_ary[$total_times])){

$ary_new[$i] = $ary_new[$i+1];

}

}

unset($ary_new[sizeof($ary_new)-1]);

$total_times += 1;

}

if ($end_ary == $order_ary || $end_ary == $order_ary) {

$not_finish = false;

}

if ($min_result == 0 || $min_result > $result) {

$min_result = $result;

$min_array = $order_ary;

}

$order_ary = add_one($order_ary);


}

return array($min_result,$min_array);

}

function add_one($order_ary){

//让数组自动添加1

$size = sizeof($order_ary);

for($i = $size-1 ;$i > -1; $i--){

if ($order_ary[$i] + 1 > ($size - $i-1) ) {

$order_ary[$i] = 0;

} else {

$order_ary[$i] = $order_ary[$i] +1;

break;

}

}

return $order_ary;

}

$ary = array(6,5,5,6);

$min_result = sand($ary);

echo 'Limit value:'.($min_result[0]);

echo '<br />Limit method:<br />';

print_r($min_result[1]);



其中函数add_one()用于使得操作的步骤是一步一步来增长.

当然,上述结果没有考虑到相同的情况,最小值相同的情况忽略不计了.但如果只要求最要值,那上述程序还可以用.
绿色夹克衫 2011-04-29
  • 打赏
  • 举报
回复
哎呀,147楼的Garsia-Wachs程序有bug,具体问题还没有找到,总之是有错,大家先忽视吧。
绿色夹克衫 2011-04-29
  • 打赏
  • 举报
回复
为了解决n = 100000规模的数据,只好搞复杂了,写了一个左偏树(还支持了一下泛型),真正的n*log(n)的方法,算10万大概1-2秒吧。用的是Hu-Tucker的算法,也是目前解决这个问题能够找到的最好的方法,当然在实现细节上还有不少优化的空间,不过就这样吧。

5.1要出去玩,只好今晚熬夜搞定这个问题了。
回来后再详细说明每种方法。

using System;
using System.Linq;

namespace CsdnTest
{
public class TreeNode<T>
{
public T Key;
public int Distance;
public TreeNode<T> Left;
public TreeNode<T> Right;
public TreeNode<T> Parent;

public TreeNode(T key, int dis, TreeNode<T> left, TreeNode<T> right)
{
Key = key; Distance = dis;
Left = left; Right = right;
}
}

public delegate int KeyComparer<T>(T T1, T T2);

public class LeftistTree<T>
{
public TreeNode<T> Root;
public static KeyComparer<T> Comparer;
public static TreeNode<T> Merge(TreeNode<T> node1, TreeNode<T> node2)
{
if (node1 == null)
return node2;
else if (node2 == null)
return node1;

if ((Comparer != null && Comparer(node1.Key, node2.Key) > 0)
|| (node1.Key.GetHashCode().CompareTo(node2.Key.GetHashCode()) > 0 && Comparer == null))
Swap<TreeNode<T>>(ref node1, ref node2);

node1.Right = Merge(node1.Right, node2);

if (node1.Right != null)
node1.Right.Parent = node1;

if (GetDistance(node1.Right) > GetDistance(node1.Left))
Swap<TreeNode<T>>(ref node1.Right, ref node1.Left);

node1.Distance = GetDistance(node1.Right) + 1;

return node1;
}

public static int GetDistance(TreeNode<T> node)
{
return node == null ? -1 : node.Distance;
}

public static void Remove(TreeNode<T> node)
{
TreeNode<T> parent = node.Parent;
TreeNode<T> newNode = Merge(node.Left, node.Right);

if (newNode != null)
newNode.Parent = parent;

if (parent != null)
{
if (parent.Left == node)
parent.Left = newNode;
else
parent.Right = newNode;
}

while (parent != null)
{
if (GetDistance(parent.Left) < GetDistance(parent.Right))
Swap<TreeNode<T>>(ref parent.Left, ref parent.Right);

if (GetDistance(parent.Right) + 1 == parent.Distance)
break;

parent.Distance = GetDistance(parent.Right) + 1;
parent = parent.Parent;
}
}

public static void Swap<U>(ref U node1, ref U node2)
{
U temp = node1;
node1 = node2;
node2 = temp;
}

public T Min
{
get { return Root.Key; }
}

public TreeNode<T> Enqueue(T value)
{
TreeNode<T> node = new TreeNode<T>(value, 0, null, null);
Root = Merge(Root, node);
return node;
}

public TreeNode<T> Dequeue()
{
TreeNode<T> minNode = Root;
Root = Merge(Root.Left, Root.Right);
return minNode;
}

public void RemoveNode(TreeNode<T> node)
{
if (node == Root)
Dequeue();
else
LeftistTree<T>.Remove(node);
}
}

public class PairNode
{
public TreeNode<Stone> Node;
public HPQueue Tree;
public PairNode(TreeNode<Stone> node, HPQueue tree)
{
Node = node;
Tree = tree;
}
}

public class Stone
{
public int Value;
public int Index;
public bool IsLeaf;
public PairNode Left;
public PairNode Right;

public Stone(int value, int index, bool isLeaf)
{
Value = value;
Index = index;
IsLeaf = isLeaf;
}

public static int Compare(Stone item1, Stone item2)
{
if (item1.Value == item2.Value)
return item1.Index - item2.Index;
else
return item1.Value - item2.Value;
}
}

public class HPQueue
{
public LeftistTree<Stone> HPQTree = new LeftistTree<Stone>();
public TreeNode<HPQueue> TreeNode;
public int Index;
public int Left = -1;
public int Right = -1;

public TreeNode<Stone> Min
{
get { return HPQTree.Root; }
}

public TreeNode<Stone> SecMin
{
get
{
if (HPQTree.Root == null || HPQTree.Root.Left == null)
return null;
else if (HPQTree.Root.Right == null)
return HPQTree.Root.Left;
else if (Stone.Compare(HPQTree.Root.Left.Key, HPQTree.Root.Right.Key) > 0)
return HPQTree.Root.Right;
else
return HPQTree.Root.Left;
}
}

public int MinSum = 0;

public void SetMinSum()
{
if(SecMin != null)
MinSum = Min.Key.Value + SecMin.Key.Value;
}

public static int Compare(HPQueue item1, HPQueue item2)
{
if (item1.MinSum == item2.MinSum)
return item1.Index - item2.Index;
else
return item1.MinSum - item2.MinSum;
}
}

class Program
{
static Stone[] Stones;
static HPQueue[] HPQs;
static LeftistTree<HPQueue> MasterTree = new LeftistTree<HPQueue>();

static void InitStones()
{
Random random = new Random(10);
int[] array = Enumerable.Range(1, 100000).Select(t => random.Next(1, 100)).ToArray();
Stones = new Stone[array.Length];

for (int i = 0; i < Stones.Length; i++)
Stones[i] = new Stone(array[i], i, true);
}

static void InitHPQs()
{
LeftistTree<HPQueue>.Comparer = HPQueue.Compare;
LeftistTree<Stone>.Comparer = Stone.Compare;
HPQs = new HPQueue[Stones.Length - 1];

for (int i = 0; i < Stones.Length - 1; i++)
{
HPQueue item = new HPQueue();
Stones[i].Right = new PairNode(item.HPQTree.Enqueue(Stones[i]), item);
Stones[i + 1].Left = new PairNode(item.HPQTree.Enqueue(Stones[i + 1]), item);

item.Left = i;
item.Right = i + 1;
item.Index = i;
item.SetMinSum();
item.TreeNode = MasterTree.Enqueue(item);
HPQs[i] = item;
}
}

static void Main(string[] args)
{
int minCost = 0;
InitStones();
InitHPQs();

for (int i = 0; i < Stones.Length - 1; i++)
{
HPQueue item = MasterTree.Dequeue().Key;

Stone min = item.HPQTree.Dequeue().Key;
Stone secMin = item.HPQTree.Dequeue().Key;

if (min.Index > secMin.Index)
LeftistTree<Stone>.Swap<Stone>(ref min, ref secMin);

Deal(min, item);
Deal(secMin, item);

min.Value += secMin.Value;
Stones[secMin.Index] = null;
minCost += min.Value;
item.HPQTree.Enqueue(min);
item.SetMinSum();
item.TreeNode = MasterTree.Enqueue(item);
}

Console.WriteLine(minCost);
Console.ReadKey();
}

private static void Deal(PairNode pair, HPQueue item)
{
if (pair != null && pair.Tree != item)
{
MasterTree.RemoveNode(pair.Tree.TreeNode);
HPQs[pair.Tree.Index] = null;
pair.Tree.HPQTree.RemoveNode(pair.Node);
item.HPQTree.Root = LeftistTree<Stone>.Merge(item.HPQTree.Root, pair.Tree.HPQTree.Root);

//修改合并后的左右节点
item.Left = Math.Min(item.Left, pair.Tree.Left);
item.Right = Math.Max(item.Right, pair.Tree.Right);

//修改左右节点对应的树
if (Stones[item.Left] != null && Stones[item.Left].Right != null)
Stones[item.Left].Right.Tree = item;

if (Stones[item.Right] != null && Stones[item.Right].Left != null)
Stones[item.Right].Left.Tree = item;
}
}

private static void Deal(Stone stone, HPQueue item)
{
if (stone.IsLeaf)
{
Deal(stone.Left, item);
Deal(stone.Right, item);
stone.Left = null;
stone.Right = null;
stone.IsLeaf = false;
}
}
}
}
jlimin 2011-04-28
  • 打赏
  • 举报
回复
等待答案中。。。。。。。

为什么排序不行呢,把最小的排在前面
秋的红果实 2011-04-27
  • 打赏
  • 举报
回复
占个地方,有时间了写个非递归的
lilicheng256 2011-04-27
  • 打赏
  • 举报
回复
随着N的增大,复杂度急剧增加
aliezeng77 2011-04-26
  • 打赏
  • 举报
回复
while条件有点小问题,更正一下:

int emerge(int A[],int n)
{
int sum1=0, sum2=0;
int i=0,j=n-1

if(n==2) return A[0]+A[1];
while(i+1<j)
{
if(sum1<=sum2)
{
sum1=sum1+A[i]
i++;
}
else{
sum2=sum2+A[j];
j++;
}
}
return emerge(A,i+1)+emerge(A+i+1,n-i-1)+sum1+sum2;
}
加载更多回复(138)

111,130

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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