题解 P1209 【[USACO1.3]修理牛棚 Barn Repair】

思路:

首先我们有一些地方木板是必须要覆盖的,那就是有牛的牛棚,所以我们可以先用一个book数组,用book[i]=1标记牛棚i有牛,之后我们用

O(最后一个有牛的牛棚编号-第一个有牛的牛棚编号+1)的时间就可以扫一遍整个数组,统计出有牛的牛棚的个数。之后由于不耻的老板供应木板是有数量限制的,所以我们在这之后还要把一些没有木板的地方连接起来,知道剩下的木板数量符合条件为止。假设有这样的一个区间,这个区间中所有的木板盖着的牛棚都是有牛的,在所有的这样的区间以外的牛棚都是没有牛的,我们先统计出这样区间有几个,之后就可以得到我们需要合并多少的区间,这样之后在把没有牛的区间长度统计出来并把每个没牛的区间的长度放入一个数组中,之后对数组进行排序,之后选出需要的长度,加在答案上就可以了。

ps:其实这道题目的解法其实就是最小生成树的简化版本

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 1e4+5;

int m,s,c;
int start=99999999,end1=-99999999;
int arr[N];
int book[N];

int main(){
    scanf("%d%d%d",&m,&s,&c);
    int tx;
    for(int i=1;i<=c;i++){
        scanf("%d",&tx);
        start=min(start,tx);
        end1=max(end1,tx);
        book[tx]++;
    }
    int sum=0;
    for(int i=start;i<=end1;i++){
        if(book[i]==1){
            sum++; //联通木条总长度
        }
    }
    int cnt=0; //连续牛棚区间的数量
    for(int i=2;i<=end1;i++){
        if(book[i]!=book[i-1] && book[i]==0){
            cnt++;
        }
    }
    if(book[end1]==1) cnt++;
    int rest=cnt-m; //需要联通的区间的数量
    int t_sum=0,head=0;
    for(int i=start;i<=end1;i++){ //获取每个未联通的区间的长度并存入数组 arr
        if(book[i]==0){
            t_sum++;
        }
        if(book[i]!=book[i-1] && book[i]==1 && i!=start){
            arr[head++]=t_sum;
            t_sum=0;
        }
    }
    if(book[end1]==0) arr[head++]=t_sum;
    sort(arr,arr+head); //也许有 Bug
    for(int i=0;i<rest;i++){
        sum+=arr[i];
    }
    printf("%d\n",sum);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lixiao189/p/9300824.html
今日推荐