正在载入在线练习界面,本页内容可直接阅读…

AK CSP › NOIP 提高 2010 第一轮真题 › 第 35 题

NOIP 提高 2010 第一轮 第 35 题:完善程序(过河问题)第 3 空

完善程序 · 堆与优先队列 · 答案 j=i+i

题目

2.(烽火传递)烽火台又称烽燧,是重要的军事防御设施,一般建在险要处或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息;夜晚燃烧干柴,以火光传递军情。在某两座城市之间有 $n$ 个烽火台,每个烽火台发出信号都有一定的代价。为了使情报准确地传递,在连续的 $m$ 个烽火台中至少要有一个发出信号。现输入 $n,m$ 和每个烽火台发出信号的代价,请计算总共最少花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确传递。

例如,有 $5$ 个烽火台,他们发出信号的代价依次为 $1,2,5,6,2$,且 $m$ 为 $3$,则总共最少花费代价为 $4$,即由第 $2$ 个和第 $5$ 个烽火台发出信号。

#include<iostream>
#include<cstring>
using namespace std;
const int SIZE=100;
int n,m,r,value[SIZE],heap[SIZE],
    pos[SIZE],home[SIZE],opt[SIZE];
    //hep[i]表示用顺序数组储存的堆heap中第i个元素的值
    //pos[i]表示opt[i]在堆heap中的位置,即heap[pos[i]]=opt[i]
    //home[i]表示heap[i]在序列opt中的位置,即opt[home[i]]=heap[i]

void swap(int i,int j)//交换堆中的第i个和第j个元素
{
    int tmp;
    pos[home[i]]=j;
    pos[home[j]]=i;
    tmp=heap[i];
    head[i]=head[j];
    heap[j]=tmp;
    tmp=home[i];
    home[i]=home[j];
    home[j]=tmp;
}
void add(int k)//在堆中插入opt[k]
{
    int i;
    r++;
    heap[r]=        ①      ;
    pos[k]=r;
             ②        ;
    i=r;
    while( (i>1) && (heap[i]<heap[i/2]) )
    {
        swap(i,i/2);
        i/=2;
    }
}
void remove(int k)//在堆中删除opt[k]
{
    int i,j;
    i=pos[k];
    swap(i,r);;
    r--;
    if(i==r+1)
       return ;
    while( (i>1)&&(heap[i]<heap[i/2]) )
    {
        swap(i,i/2);
        i/=2;
    }
    while(i+i<=r)
    {
        if( (i+i+1<=r) && (heap[i+i+1]<heap[i+i]) )
            j=i+i+1;
        else
                    ③       ;
        if(heap[i]>heap[j])
        {
                    ④        ;
            i=j;
        }
        else
            break;
    }
}

int main()
{
    int i;
    cin>>n>>m;
    for(i=1;i<=n;i+++)
        cin>>value[i];
    r=0;
    for(i=1;i<=m;i++)
    {
        opt[i]=value[i];
        add(i);
    }
    for(i=m+1;i<=n;i++)
    {
        opt[i]=         ⑤       ;
        remove(        ⑥       );
        add(i);
    }
    cout<<heap[1]<<endl;
    return 0;
}

本小题

③处应填( )

答案

j=i+i

题解

考点定位

本题(烽火传递第③空)考「堆删除下沉选子」,对应大纲 3.2.3 堆(难度【4】)。

解题过程

③处在 remove 的下沉循环:选两个孩子中较小者:

``cpp else j = i + i; // 左孩子 ``

(有右孩子且右更小则 j=i+i+1,否则左孩子。)答案:j=i+i。

易错提醒

① 完全二叉堆 1 起编号:孩子 i×2 与 i×2+1;② 与第 29 行的上浮循环(与父比较)区分方向。

真题版权归 CCF 所有,本站仅用于非商业教学用途。页面加载后可直接在线作答,作答记录保存在本浏览器或账号中。 京ICP备2026056990号-1 京公网安备11010502062986号