• 洛谷P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G


    [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G

    题目描述

    在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。

    每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n − 1 n-1 n1 次合并之后, 就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。

    因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 1 1 1 ,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。

    例如有 3 3 3 种果子,数目依次为 1 1 1 2 2 2 9 9 9 。可以先将 1 1 1 2 2 2 堆合并,新堆数目为 3 3 3 ,耗费体力为 3 3 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 12 12 ,耗费体力为 12 12 12 。所以多多总共耗费体力 = 3 + 12 = 15 =3+12=15 =3+12=15 。可以证明 15 15 15 为最小的体力耗费值。

    输入格式

    共两行。
    第一行是一个整数 n ( 1 ≤ n ≤ 10000 ) n(1\leq n\leq 10000) n(1n10000) ,表示果子的种类数。

    第二行包含 n n n 个整数,用空格分隔,第 i i i 个整数 a i ( 1 ≤ a i ≤ 20000 ) a_i(1\leq a_i\leq 20000) ai(1ai20000) 是第 i i i 种果子的数目。

    输出格式

    一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 2 31 2^{31} 231

    样例 #1

    样例输入 #1

    3 
    1 2 9
    
    • 1
    • 2

    样例输出 #1

    15
    
    • 1

    提示

    对于 30 % 30\% 30% 的数据,保证有 n ≤ 1000 n \le 1000 n1000

    对于 50 % 50\% 50% 的数据,保证有 n ≤ 5000 n \le 5000 n5000

    对于全部的数据,保证有 n ≤ 10000 n \le 10000 n10000

    思路,这个题我第一次的想法就是把数据从小到大,然后依次合并,最后就能得到结果!
    后来发现,虽然最小的两个合并,但是可能两个小的合并后的数据大于下一个,再次合并就是有问题的,因此,我又想到一种方法,就是每次遍历找到最小的两个,然后将这两个合并成一个大数字,然后把当初小的那个数字变成-1,然后把大数字赋值到数组内,再进行一次遍历,找到最小的两个,又进行合并,这样每次我遍历时候都把负数去掉,以此循环遍历能得到最后的结果!
    该算法的时间复杂度是O(n*n)(应该不算优),如果广大网友有更好的想法,欢迎q我!
    代码如下(编译器是dev,语言是C语言):

    #include
    int n,a[10005],temp,i,j,sum=0,minmin,minmax,mintemp=0,maxtemp=1,k,s,tempshuzu;
    int main(){
        scanf("%d",&n);
        for(i = 1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        minmin = a[1],minmax = a[2];
        mintemp = 1,maxtemp = 2;
        for(i = 1;i<n;i++){
        	for(s = 1;s<=n;s++){
        		if(a[s]<0)
        			continue;
        		minmin = a[s];
        		mintemp = s;
        		break;
    		}
    		for(s = 1;s<=n;s++){
        		if((a[s]<0)||(s == mintemp))
        			continue;
        		minmax = a[s];
        		maxtemp = s;
        		break;
    		}
    		if(minmax<minmin){
    			temp = minmax;
    			minmax = minmin;
    			minmin = temp;
    			tempshuzu = mintemp;
    			mintemp = maxtemp;
    			maxtemp = tempshuzu;
    			
    		}
        	for(j = 1;j<=n;j++){
        		if(a[j] <0){
        			continue;
    			}
        		if((a[j]<minmax)&&(j!=mintemp)){
        			if(a[j]<minmin){
        				minmax = minmin;
        				minmin = a[j];
        				//minmax = minmin;
        				maxtemp = mintemp;
        				mintemp = j;
    				}else{
    					minmax = a[j];
    					maxtemp = j;
    				}
    			}
    		}
    		sum = sum + minmin +minmax;
    		a[maxtemp] = minmin+minmax;
    		a[mintemp] = -1;
    	}
    	printf("%d",sum);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
  • 相关阅读:
    TCP粘包拆包的原因及解决办法
    div的并列和包含关系
    树存储结构-二叉树
    系统安全分析与设计
    Tetrate刘晗:SkyWalking原生eBPF探针实战
    程序设计与算法(三)C++面向对象程序设计笔记 第七周 输入输出和模板
    shell 监听指定日志变化进行相关业务处理
    HLS最全知识库
    Java第3天(使用记事本编写运行Java程序)
    2018-2019 ACM-ICPC, Asia Nanjing Regional Contest G. Pyramid(组合数学 计数)
  • 原文地址:https://blog.csdn.net/weixin_43708800/article/details/128040123