小Y写文章 (二分+二分图最大匹配)

本文介绍了一个程序设计竞赛问题的解决方案,通过二分查找和最大匹配算法来确定如何插入额外元素以最小化数组中相邻元素的最大差值。文章详细解释了算法步骤,并提供了完整的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题埃森哲杯第十六届上海大学程序设计联赛春季赛暨上海高校金马五校赛 J

题意

给定n个数的数组,插入m个数,可以在最前面也可以在最后面,但是一个位置只能插入一个数,使ans最小
ans=max(abs(a[i+1]-a[i]))

解析

二分ans,对面每个ans,判断是否可以将m个数都插入

问题的怎么判断

既然假设已经知道了ans,那么哪些数可以插在哪些位置就知道了,m个数对应n+1个位置,二分图最大匹配就好了

但是还有一个问题,那些没有插入的位置也有一个val,即位置前后原数组数之差,那么就要改善一下

那些没有插入的地方看成插入一个空的数,问题转化成n+1个位置插入n+1个数

代码

#include<bits/stdc++.h>
using namespace std;
#define mmm(a,b) memset(a,b,sizeof(a))

int n,m;
int a[209],b[209];
int M[209][209];

//预处理第i个插入项插在第j个空位的val
void init(){//并没有有插入的空和没插入的空的区别,插入的有val,没插入的也有val
    for(int i=1;i<=m;i++){
        M[i][0]=abs(a[1]-b[i]);
        M[i][n]=abs(a[n]-b[i]);
        for(int j=1;j<n;j++){
            M[i][j]=max(abs(a[j]-b[i]),abs(a[j+1]-b[i]));
        }
    }
    for(int i=m+1;i<=n+1;i++){
        M[i][0]=M[i][n]=0;
        for(int j=1;j<n;j++){
            M[i][j]=abs(a[j]-a[j+1]);
        }
    }
}
//***********************************************************
int match[209],vis[209];

//插入项序号 1~n+1 (m以后的为空插入项)  空位序号 0~n

int fin(int h,int len){
    for(int i=0;i<=n;i++){//试图找到一个可以插入的空
        if(vis[i]||M[h][i]>len)continue;
        vis[i]=1;
        if(match[i]==0||fin(match[i],len)){
            match[i]=h;return 1;
        }
    }
    return 0;
}

int judge(int h){//1表示这个间距可以插入
    mmm(match,0);
    int ans=0;
    for(int i=1;i<=n+1;i++){//对于每个插入项
        mmm(vis,0);
        if(fin(i,h))ans++;
    }
    if(ans==n+1)return 1;
    return 0;
}
//***********************************************************

int main(){
    int t;scanf("%d",&t);while(t--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",a+i);
        for(int i=1;i<=m;i++)scanf("%d",b+i);
        init();
        int l=0,r=1e9+7;
        while(r-l>1){
            int mid=r+l>>1;
            if(judge(mid))r=mid;
            else l=mid;
        }
        printf("%d\n",r);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值