1 条题解

  • 5
    @ 2023-10-19 21:28:38

    课堂听课笔记:【DOGE】

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    int heap[10001];  //模拟 堆(完全二叉树),根节点:heap[1] 
    int heap_size;  //存储  堆 heap 的大小 
    
    void put(int d){  //向堆 heap 中添加元素 d
    /* put 函数  算法:
    1. 在堆尾加入元素 d,并把堆尾的这个结点置为当前结点
    2. 比较当前结点元素与它的父结点元素的大小。【假设 当前结点为 i,则 当前结点的父结点 为 i/2】
    如果 当前结点<它的父结点,则 交换它们的元素,并把当前结点的父结点置为当前结点,转 步骤2
    如果 当前结点>=它的父结点,则 转 步骤3
    3. 结束(return ;)
    */
        int now, next;  //now:存储 当前结点; next:存储 当前结点的父结点
    	
    	//步骤 1
    	heap[++heap_size] = d;  //向堆尾加入元素 d,堆的大小自增 1 
    	now = heap_size;  //设置 当前结点 now 为堆尾结点
    	
    	//步骤 2
    	while(now > 1){  //重复 比较当前结点元素与它的父结点元素的大小,直到 当前结点的父结点为根节点(heap[1]),即 当前结点/2==1 
    		next = now/2;  //设置 当前结点的父结点 next 为 当前结点/2
    		
    		//当前结点>=它的父结点:put 函数 结束
    		if(heap[now] >= heap[next]) break;  //退出循环 
    		//当前结点<它的父结点:交换 当前结点(heap[now]) 与 它的父结点(heap[next]) 的元素 
    		swap(heap[now], heap[next]);  //swap(a, b):交换 a 与 b 的值,头文件:iostream 
    		now = next;  //设置 当前结点 now 为 当前结点的父结点 next
    	}
    
        return ;  //步骤 3
    }
    
    int get(){  //从堆 heap 中取出并删除 最小元素
    /* get 函数  算法:
    1. 取出 堆根结点元素
    2. 把 堆尾的结点(heap[len],暂且用 len 表示 heap_size) 转移到 根(heap[1])的位置,将根覆盖,堆的大小减 1 
    3. 把根结点置为当前父结点 parent
    4. 如果 parent 无孩子【parent > len/2,假设 当前结点为 i,则 当前结点的左孩子 为 i*2,右孩子 为 i*2+1】
    【对于 parent > len/2 时,若 parent=len/2+1,则 parent 的左孩子=len+2,右孩子=len+3。len+3>len+2>len(堆的长度),说明 parent 无孩子】,
    则 转 步骤6;
    否则【parent <= len/2】,把 parent 的两(或一,当且仅当 parent == len/2 时)个孩子中元素最小的孩子 置为当前父结点的子结点 son
    5. 比较 当前父结点(parent) 与 它的子结点(son) 的元素大小。 
    如果 当前父结点>当前父结点的子结点,则 交换它们的元素,把 当前父结点的子结点 指向 当前父结点,转 步骤4;
    如果 当前父结点<=当前父结点的子结点,则 转 步骤6
    6. 结束(return ;)
    */
    	int now, next, res;  //now:存储 当前父结点; next:存储 当前父结点的子结点中元素最小的子结点; res:临时存储 根结点的元素
    	
    	//步骤 1
    	res = heap[1];  //临时存储 堆 heap 根结点的元素
    	
    	//步骤 2
    	heap[1] = heap[heap_size--];  //设置 堆根结点(heap[1]) 为 堆尾结点,堆的大小自减 1  
    	
    	//步骤 3
    	now = 1;  //设置 当前父结点 now 为 根结点
    	
    	//步骤 4
    	while(now*2 <= heap_size){  //重复 比较当前父结点元素与它的子结点元素的大小,直到 当前父结点的子结点为超出堆的大小(heap_size),即 当前结点*2 > heap_size 
    		next = now*2;  //先设置 当前父结点的子结点 next 为 当前父结点的左孩子(此时 next 不一定 存储的是元素最小的子结点,需要进行比较)
    		
    		//next < heap_size:判断 当前父结点是否有右孩子; heap[next+1]<heap[next]:判断 当前父结点的右孩子(假设存在右孩子)是否小于当前父结点的左孩子
    		if(next<heap_size && heap[next+1]<heap[next]) next++;  //经过比较 设置 next 为 当前父结点中元素最小的子结点
    		
    		//步骤 5
    		//当前父结点<=它的子结点中元素最小的子结点:get 函数 结束
    		if(heap[now] <= heap[next]) break;  //退出循环 
    		//当前父结点>当前父结点的子结点:则 交换 当前父结点(heap[now]) 与 它最小的子结点(heap[next]) 的元素
    		swap(heap[now], heap[next]);  //swap(a, b):交换 a 与 b 的值,头文件:iostream 
    		now = next;  //设置 当前父结点 now 为 当前父结点的子结点中元素最小的子结点 next
    	}
    	
    	//步骤 6
    	return res;  //返回 取出的根结点的元素
    }
    
    
    int main(){
        int n;  //存储 果子的种类数目 
        scanf("%d", &n);  //输入  果子的种类数目 n 
    
        for(int i=0; i<n; i++){
        	int x;  //存储 第 i 种果子的数目
            scanf("%d", &x);  //输入  第 i 种果子的数目 x 
    
            put(x);  //向堆 heap 中添加元素 x 
        }
        
        int ans=0;  //存储 最小体力耗费值
    	for(int i=0; i<n-1; i++){  //合并果子次数:n-1 
    		int x=get(), y=get();  //从堆 heap 中依次取出并删除 最小元素 x, y(取出并删除 元素 x 后 y 为 此时的最小元素)
    		ans += x + y;  //最小体力耗费值 增加 x+y
    		put(x+y);  //向堆 heap 中添加元素 x+y(将已合并的果子重新加入堆中,进行下一轮合并处理)
    	}
     
    	printf("%d\n", ans);  //输出  最小体力耗费值 ans
    
        return 0;
    }
    

    如有BUG,敬请指正!👀️

    • @ 2023-11-9 13:19:38

      STL 方法:

      #include<cstdio>
      #include<queue>
      using namespace std;
      
      priority_queue<int, vector<int>, greater<int> > heap;  //定义 堆(先序队列) 结构类型 heap
      
      int main(){
          int n;  //存储 果子的种类数目 
          scanf("%d", &n);  //输入  果子的种类数目 n 
      
          for(int i=0; i<n; i++){
          	int x;  //存储 第 i 种果子的数目
              scanf("%d", &x);  //输入  第 i 种果子的数目 x 
      
              heap.push(x);  //向堆 heap 中添加元素 x 
          }
          
          int ans=0;  //存储 最小体力耗费值
      	for(int i=0; i<n-1; i++){  //合并果子次数:n-1 
              //从堆 heap 中依次取出并删除 最小元素 x, y(取出并删除 元素 x 后 y 为 此时的最小元素)
      		int x=heap.top();  //从堆 heap 中取出 队首 元素
              heap.pop();  //堆 heap 删除 队首 元素
              int y=heap.top();  //从堆 heap 中取出 队首 元素  
              heap.pop();  //堆 heap 删除 队首 元素
              
      		ans += x+y;  //最小体力耗费值 增加 x+y
      		heap.push(x+y);  //向堆 heap 中添加元素 x+y(将已合并的果子重新加入堆中,进行下一轮合并处理)
      	}
       
      	printf("%d\n", ans);  //输出  最小体力耗费值 ans
      
          return 0;
      }
      

信息

ID
135
时间
1000ms
内存
128MiB
难度
7
标签
递交数
117
已通过
25
上传者