最小函数值

P2085 最小函数值
题目描述

有n个函数,分别为F1,F2,…,Fn。定义Fi(x)=Aix^2+Bix+Ci (x∈N*)。给定这些Ai、Bi和Ci,请求出所有函数的所有函数值中最小的m个(如有重复的要输出多个)。

输入输出格式

输入格式:
输入数据:第一行输入两个正整数n和m。以下n行每行三个正整数,其中第i行的三个数分别位Ai、Bi和Ci。Ai<=10,Bi<=100,Ci<=10 000。

输出格式:
输出数据:输出将这n个函数所有可以生成的函数值排序后的前m个元素。这m个数应该输出到一行,用空格隔开。

引用一篇题解的解释部分:

对于上述问题的优化方法,比较好的是用堆来做。思路是这样的:首先,我们可以在所有“箭头”指向1的时候,对所有箭头对应的函数值建立小根堆;然后,每次从堆顶取走那个数,并将其所对应的“箭头”指向下一个函数值,然后把这个新的函数值代替那个取走的函数值放在堆顶,并自顶向下维护堆(大家可以证明一下,一直这样操作下去,堆的性质恒成立)。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct T
{
	int m,mi,i;//最小函数值,这个值对应的x,编号 
}x[10005];
int A[10005],B[10005],C[10005];
int l=0;
void swaps(int a,int b)
{
	int t;
	t=x[a].m;
	x[a].m=x[b].m;
	x[b].m=t;
	t=x[a].mi;
	x[a].mi=x[b].mi;
	x[b].mi=t;
	t=x[a].i;
	x[a].i=x[b].i;
	x[b].i=t;
} 
void put(T d)
{
    int now,next;
    x[++l]=d;
    now=l;
    while(now>1)
    {
        
        next=now>>1;
        if(x[now].m>=x[next].m)
        {
            break;
        }
        swaps(now,next);
        now=next;
    }
}
T get()
{
    int now,next;
    T res=x[1];
    x[1]=x[l--];
    now=1;
    while(2*now<=l)
    {
        next=now<<1;
        if(next<l && x[next].m>x[next+1].m)
        {
            next++;
        }
        if(x[now].m<=x[next].m)
        {
            break;
        }
        swaps(now,next);
        now=next;
    }
    return res;
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	T k;
	for(int i=0;i<n;i++)
	{
		scanf("%d%d%d",&A[i],&B[i],&C[i]);
		k.i=i;//这里不能直接用x[i],不然会乱 
		k.m=A[i]+B[i]+C[i];
		k.mi=1;
		put(k);
	}
	for(int i=0;i<m;i++)
	{
		k=get();
		printf("%d ",k.m);
		k.mi++;
		k.m=A[k.i]*k.mi*k.mi+B[k.i]*k.mi+C[k.i];
		put(k);
	}
	return 0;
}
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#define N 10005
using namespace std;
int A[N],B[N],C[N];
struct T
{
	int m,mi,i;
};
bool operator < (T a,T b)
{
	return a.m>b.m;
}
priority_queue<T> x;
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	T t;
	for(int i=0;i<n;i++)
	{
		scanf("%d%d%d",&A[i],&B[i],&C[i]);
		t.m=A[i]+B[i]+C[i];
		t.mi=1;
		t.i=i;
		x.push(t);
	}
	for(int i=0;i<m;i++)
	{
		t=x.top();
		x.pop();
		printf("%d ",t.m);
		t.mi++;
		t.m=A[t.i]*t.mi*t.mi+B[t.i]*t.mi+C[t.i];
		x.push(t);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值