YbtOJ 「数据结构」 第1章 堆的应用
堆的应用
A. 【例题1】合并果子
每次将权值最小的前两个揪出来合并即可
#include <bits/stdc++.h>
#define pii pair < int , int >
using namespace std;
priority_queue < int , vector < int > , greater < int > > q;
int main()
{
int n , temp , ans = 0;
scanf ( "%d" , &n );
for ( int i = 1 ; i <= n ; i ++ )
{
scanf ( "%d" , &temp );
q.push(temp);
}
while ( q.size() > 1 )
{
int add = 0;
add += q.top();q.pop();
add += q.top();q.pop();
ans += add;
q.push(add);
}
printf ( "%d" , ans );
return 0;
}
B. 【例题2】序列合并
将两个数组排序 枚举第一个 并在第二个中从前到后判断 动态维护两个数组的和 如果当前这个加和已经大于堆的最大值就跳出循环 优化时间复杂度
最后倒序输出即可
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
priority_queue <int> q;
int n , a[N] , b[N] , ans[N];
signed main ()
{
int n = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for ( int i = 1 ; i <= n ; i ++ ) b[i] = read();
sort ( a + 1 , a + n + 1 );
sort ( b + 1 , b + n + 1 );
for ( int i = 1 ; i <= n ; i ++ )
for ( int j = 1 ; j <= n ; j ++ )
{
int temp = a[i] + b[j];
if ( q.size() < n ) q.push ( temp );
else
{
if ( q.top() > temp ) q.pop() , q.push ( temp );
else break;
}
}
for ( int i = n ; i ; i -- ) ans[i] = q.top() , q.pop();
for ( int i = 1 ; i <= n ; i ++ ) printf ( "%d " , ans[i] );
return 0;
}
C. 【例题3】龙珠游戏
维护一个链表 将所有的龙珠都读入之后 用值域从高到低枚举(因为龙珠的下标和值都是
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , ans , a[N] , nxt[N] , lst[N];
signed main ()
{
n = read();
for ( int i = 1 ; i <= n ; i ++ )
{
a[i] = read();
nxt[a[i-1]] = a[i];
lst[a[i]] = a[i-1];
}
for ( int i = n ; i >= 1 ; i -- )
{
if ( nxt[i] )
{
printf ( "%d %d " , i , nxt[i] );
nxt[lst[i]] = nxt[nxt[i]];
lst[nxt[nxt[i]]] = lst[i];
nxt[nxt[i]] = 0;
}
}
return 0;
}
D. 【例题4】工作安排
反悔贪心 维护一个优先队列 优先队列大小为当前时间 权值为所有安排的事的利润大小
先按照时间排序 每次判断最低值和当前利润的大小关系 如果有更大利润则替换
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 5;
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
priority_queue < int , vector<int> , greater<int> > q;
int n , ans;
struct node { int d , p; } a[N];
signed main ()
{
n = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i].d = read() , a[i].p = read();
sort ( a + 1 , a + n + 1 , [](const node a , const node b) { return a.d < b.d; } );
for ( int i = 1 ; i <= n ; i ++ )
{
if ( q.size() < a[i].d ) q.push ( a[i].p ) , ans += a[i].p;
else
{
int temp = q.top();
if ( temp < a[i].p )
{
ans -= temp;
q.pop();
ans += a[i].p;
q.push ( a[i].p );
}
}
}
printf ( "%lld" , ans );
return 0;
}
E. 1.家庭作业
贪心策略:先按照截止时间排序 每次先将这次的时间长度加上 如果超过了这次的合法时间 那么尝试用之前的
如果这个时间削减至0了 那么寻找下一个
注意:如果这一次削减时间达到了阈值 那么现在的截止时间应该截止到现在这一个事件的截止时间 而不是这一个削减事件的截止时间
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 5;
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n;
double tmp = 0 , ans = 0;
struct node
{
double a , b , d;
friend bool operator < ( node a , node b ) { return a.a < b.a; }
}a[N];
priority_queue<node> q;
signed main ()
{
n = read();
for ( int i = 1 ; i <= n ; i ++ ) cin >> a[i].a >> a[i].b >> a[i].d;
sort ( a + 1 , a + n + 1 , [](const node a , const node b) { return a.d < b.d; } );
for ( int i = 1 ; i <= n ; i ++ )
{
tmp += a[i].b;
q.push ( a[i] );
double delta = tmp - a[i].d;
while ( delta > 0 )
{
node u = q.top(); q.pop();
if ( u.b >= delta )//这一次够了
{
ans += delta / u.a;
u.b -= delta;
delta = 0;
tmp = a[i].d;
if ( u.b != 0 ) q.push(u);
}
else//这一次不够
{
ans += u.b / u.a;
tmp -= u.b;
delta -= u.b;
}
}
}
printf ( "%.2lf" , ans );
return 0;
}
F. 2.选数游戏
容易发现只有每一列被访问的行数有用 那么我们考虑贪心
从左向右枚举最后的列数 每遇到一列就将一整列直接加入堆 对于每一次加入的答案 我们都弹出数 直到队列中的数的个数小于等于
然后再加上最后一次弹出的节点与剩余步数的乘积
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1e6 + 5;
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n , m , k , sizee , sum , maxx , ans;
priority_queue < int , vector < int > , greater < int > > q;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read() , k = read();
for ( int i = 1 ; i <= min ( m , k ) ; i ++ )//枚举最右面是哪一行
{
int temp = read();
q.push ( temp );
sizee += n , sum += n * temp;//将一整列加入堆
while ( sizee > k && !q.empty() )
{
int u = q.top();
q.pop();
sizee -= n - 1 , sum -= ( n - 1 ) * u;
maxx = u;
}
ans = max ( ans , sum + min ( n , k - sizee ) * maxx );
}
cout << ans << endl;
return 0;
}
G. 3.内存管理
开一个优先队列
每次操作之前 先将所有不合法的节点全部扔出队列 再进行查询
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
const int N = 1e6 + 5;
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n , vis[N];
priority_queue < int , vector<int> , greater<int> > q1;
int head = 1 , tail = 0 , x;
char op;
pii q2[N];//<编号,时间>
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
for ( int i = 1 ; i <= 30000 ; i ++ ) q1.push(i);
while ( cin >> x >> op )
{
while ( head <= tail && q2[head].se + 600 <= x )
{
vis[q2[head].fi] --;
if ( !vis[q2[head].fi] ) q1.push(q2[head].fi);
head ++;
}
if ( op == '+' )
{
int u = q1.top(); q1.pop();
vis[u] = 1 , q2[++tail] = mkp ( u , x );
cout << u << endl;
}
else
{
int y = read();
if ( vis[y] )
{
cout << "+" << endl;
vis[y] ++;
q2[++tail] = mkp ( y , x );
}
else cout << "-" << endl;
}
}
return 0;
}
H. 4.火车载客
九个月前的答辩代码 题解和新代码留坑
#include <bits/stdc++.h>
#define int long long
#define se second
#define fi first
#define pii pair < int , int >
using namespace std;
const int N = 6e5 + 5;
int n , k , c , tot , sum , ans;
struct train
{
int st , end , num , id;//num个人,起始站点是st,结束站点是end
bool operator<(const train& a)const{return end<a.end;}
}a[N];
struct T
{
int time , id , op;//time是下车或者上车时间,id是操作顺序 , op = 0是上车,op = 1是下车
bool operator < ( const T &a ) const { return time != a.time ? time < a.time : op > a.op; };
}b[N];
priority_queue < train > q;
signed main()
{
scanf ( "%lld%lld%lld" , &k , &n , &c );
for ( int i = 1 , s , t , p ; i <= k ; i ++ )
{
scanf ( "%lld%lld%lld" , &s , &t , &p );
a[i] = (train) { s , t , p , 0 };
b[++tot] = (T) { s , i , 0 };
b[++tot] = (T) { t , i , 1 };
}
sort ( b + 1 , b + 1 + tot );
for ( int i = 1 ; i <= tot ; i ++ )
{
int id = b[i].id;
if ( b[i].op == 0 )//上车
{
while ( !q.empty() && q.top().end < b[i].time )
{
a[q.top().id].id = 0;
q.pop();
}
while ( sum < c && a[id].num )
{
int add = min ( c - sum , a[id].num );
a[id].id += add;
a[id].num -= add;
q.push ( ( train ) { a[id].st , a[id].end , add , id } );
sum += add;
}
while ( !q.empty() && a[id].num && a[id] < q.top() )//最后面上车的人下车
{
train temp = q.top() ; q.pop();
int add = min ( a[id].num , temp.num );
temp.num -= add;
a[temp.id].id -= add;
a[id].id += add;
a[id].num -= add;
if ( temp.num ) q.push ( temp );
q.push ( ( train ) { a[id].st , a[id].end , add , id } );
}
}
else//下车力 (喜)
{
ans += a[id].id;//达到目标的总人数
sum -= a[id].id;//当前车上人数
a[id].id = 0;
}
}
printf ( "%lld" , ans );
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】