石子合并问题C语言求优秀算法 Posted 2023-04-13
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了石子合并问题C语言求优秀算法相关的知识,希望对你有一定的参考价值。
这个问题问问上曾有人问过,问的是PASCAL语言的。其实语言无所谓,在下在这里试求有没有更简单的算法。问题:你有一堆石头质量分别为W1,W2,W3...WN.(W<=100000)现在需要你将石头合并为两堆,使两堆质量的差的绝对值为最小。 输入:第一行为整数N(1<=N<=20),表示有N堆石子。第二行:是n个数,为每堆石子的质量。 输出:一行。只需输出合并后两堆的质量差的绝对值的最小值样例:输入:55 8 13 27 14输出:3 我的算法:我想的是一个笨办法,我把该题转化成另一个问题就是:给你一些数,在他们中间穷举取遍+、-号,进行运算最后得出的数取绝对值,求最小绝对值。根据这个思路,我将用于存放石头质量的数组a[20]每个元素都赋初值0,在进行输入石头质量。如上题输入后数组就变为5 8 13 27 14 0 0 0 0……然后用19个循环来穷举中间的+、-号,最后得出的绝对值如果比以前的小,则替换,否则不替换,最终得出的是最小绝对值。但19个循环太麻烦了啊,程序显得冗长。我想问有没有更优秀的算法??谢谢各位了。
先将石头求和再除2得m,求<=m得那一堆石头,再用背包法(动态规划思想,高效)或直接回朔搜索(20较小,也会轻松搞定)。 一般动态规划相比搜索写代码要简单多,但背包那问题涉及到内存的申请和释放等指针问题就有点列外啦,呵呵,小弟也没写,简单指导下。抛砖引玉。。。。。
参考技术A
看我的,用逻辑尺方法 #include <stdio.h> #include <stdlib.h> #include <math.h> main() int *w;/* 石子的质量数组 */ int *a; /* 逻辑尺。形如101100... 0表示在第一组,1表示在第二组 */ int n;/* 石子堆数 */ long pn; /* pn=2^n-1 排列组合的次数 */ long p; /* pn的临时变量,即排列组合的对应的十进制数 */ int i; /*循环变量*/ int sum1,sum2; /* 两堆石子的质量之和*/ int sub=0; /*两堆石子的质量差*/ int PN; /* sub最小时的排列组合之数*/ /*读入数据*/ printf("n="); scanf("%d",&n); /*动态分配内存,生成相应大小的数组*/ w=(int *)malloc(n*sizeof(int)); a=(int *)malloc(n*sizeof(int)); /*读入石子质量,并设最小质量的差为全部石子的质量之和,即设一个最大的值 */ for(i=0;i<n;i++) scanf("%d",&w[i]); sub+=w[i]; /*计算排列组合次数*/ pn=(int)pow(2,n)-1; while(pn>0) /*生成pn排列组合数对应的逻辑尺*/ p=pn; for(i=0;i<n;i++) a[i]=p%2; p=p/2; /*按逻辑尺计算两堆的质量*/ sum1=sum2=0; for(i=0;i<n;i++) if(a[i]==0)sum1+=w[i]; else sum2+=w[i]; /*确定当前最小的质量差,并记录组合数于PN中*/ if(abs(sum1-sum2)<sub) sub=abs(sum1-sum2); PN=pn; /*下一个组合数*/ pn--; /*输出结果*/ /*如何分堆*/ p=PN; for(i=0;i<n;i++) a[i]=p%2; p=p/2; printf("第一堆:"); for(i=0;i<n;i++) if(a[i]==0)printf("%d ",w[i]); printf("\n第二堆:"); for(i=0;i<n;i++) if(a[i]==1)printf("%d ",w[i]); printf("\n质量差:%d\n",sub);
参考技术B
我觉得你的方法类似于枚举。用2进制划分比较明确。 从题给的数据量来看,使用枚举时间的复杂度是够的2^19 可以考虑使用动态规划,但是时间复杂度不会太大改善。
参考技术C
我想的一个方法,这样做:先求出总重量,再求出分成两堆的重量m,然后用剩下的石子来凑m的重量,找到一个最接近于m的方法,应该就可可以了吧。 先从小往大加,如果超了的话,就停止加大的,然后扔小的。。。这样一直找到最接近的。。
算法提高 合并石子(DP)
问题描述
在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有石子合并成一堆的最小花费。
输入格式
输入第一行包含一个整数n,表示石子的堆数。 接下来一行,包含n个整数,按顺序给出每堆石子的大小 。
输出格式
输出一个整数,表示合并的最小花费。
样例输入
5 1 2 3 4 5
样例输出
33
数据规模和约定
1<=n<=1000, 每堆石子至少1颗,最多10000颗。
题解
#include<stdio.h>
#include <stdlib.h>
#define INIF 0x3f3f3f3f
int N;
int dp[1001 ][1001 ] = {0 };
int sum[1001 ][1001 ];
int num[1001 ];
void minsz()
{
int i, j, k, t, len, minx;
for (i = 1 ; i <= N; i++)
{
sum[i][i] = num[i];
for (j = i + 1 ; j <= N; j++)
{
sum[i][j] = sum[i][j-1 ] + num[j];// 计算堆到堆的距离
}
}
for (j = 2 ; j <= N; j++)
{
for (i = j-1 ; i > 0 ; i--)
{
minx = INIF;
dp[i][j] = INIF;
for (k = i; k < j; k++)
{
t = dp[i][k] + dp[k+1 ][j] + sum[i][j];
if (t < minx)
minx = t;
}
dp[i][j] = minx;
}
}
printf( " %d\n " , dp[1 ][N]);
}
int main()
{
int i;
scanf( " %d " , &N);
for (i = 1 ; i <= N; i++)
{
scanf( " %d " , &num[i]);
}
minsz();
return 0 ;
}
View Code
以上是关于石子合并问题C语言求优秀算法的主要内容,如果未能解决你的问题,请参考以下文章
石子合并问题
c语言有序链表合并,我找不到问题所在,求纠错!!
求指教,以下皆用数组在c语言里编写程序
c语言求1-1000素数的算法问题
2018年全国多校算法寒假训练营练习比赛(第三场) 小牛再战(博弈)
求 算法:C语言实现 的PDF