poj2442Sequence(堆)

题目
思路:
m个长度为n的序列,每个序列中任取一个,构成 n m n^m nm 个和,求其中最小的n个和

  1. 当m=2时,求2个序列中,任取一个所构成和中的n个最小和,
  • 将2个序列从小到大排序,最小的一定是 A [ 1 ] + B [ 1 ] A[1]+B[1] A[1]+B[1] ,那么下一个最小的是 m i n ( A [ 1 ] + B [ 2 ] , A [ 2 ] + B [ 1 ] ) min(A[1]+B[2],A[2]+B[1]) min(A[1]+B[2],A[2]+B[1]) ,若此时最小的为A[2]+B[1],下一个最小状态从当前最小状态的下标进行移动,那么下一个最小的为 m i n ( A [ 1 ] + B [ 2 ] , A [ 2 ] + B [ 2 ] , A [ 3 ] + B [ 1 ] ) min(A[1]+B[2],A[2]+B[2],A[3]+B[1]) min(A[1]+B[2],A[2]+B[2],A[3]+B[1]) ,,A[2]+B[2]=A[2]+B[1],j+1,A[3]+B[1]=A[2]+B[1],i+1
  • 但某个状态时A[1]+B[2]也能够得到A[2]+B[2],会导致重复进入堆中,
  • 那么我们规定如果上一次j+1过一次,那么此次j仍然只能+1i不变,此状态下将i = j这一相同情况留给i<j这一状态来达到,所以i = j这一情况不会重复
  • 堆将A[i]+B[j]作为权值,将(i,j,bool)插入堆中,每次取堆顶点形成前n个最小的和,
  • m>2时,将2形成的最小和与第3个序列进行同样的操作.
    代码太长写了1.5个小时,被数据卡了
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
struct node {
    int i;
    int j;
    bool flag;
    long long sum;
    bool operator<(const node& t)const {
        return (this->sum)>(t.sum);//小根堆
    }
};
priority_queue<node> que;
vector <int> min_val;
vector <int> numa,numb;
int main() {
    freopen("a.txt","r",stdin);
    int times;
    scanf("%d",&times);
    while ( times--) {
        int m,n;
        scanf("%d%d",&m,&n);//m个长度为n的序列
        for (int j=0;j<n;j++) {
            int numtemp;
            scanf("%d",&numtemp);
            numa.push_back(numtemp);
        }
        sort(numa.begin(),numa.end());

        for (int i=0;i<(m-1);i++) {//m个数列,合并m-1次
            for (int j=0;j<n;j++) {
                int numtemp;
                scanf("%d",&numtemp);
                numb.push_back(numtemp);
            }
            sort(numb.begin(),numb.end());
            //合并
//            printf("1");
//            return 0;

            node t;
            t.i=0; t.j=0; t.flag=false; t.sum=numa[0]+numb[0];
            que.push(t);
            for (int k=0;k<n;k++) {
                node t=que.top();
                que.pop();
                min_val.push_back(t.sum);

                if( t.flag == false ){
                    node a,b;
                    a.i=t.i+1; a.j=t.j; a.flag=false; a.sum=numa[a.i]+numb[a.j];
                    b.i=t.i; b.j=t.j+1; b.flag=true; b.sum=numa[b.i]+numb[b.j];
                    que.push(a);
                    que.push(b);
                } else {
                    node b;
                    b.i=t.i; b.j=t.j+1; b.flag=true; b.sum=numa[b.i]+numb[b.j];
                    que.push(b);
                }

            }
//            for (int i=0;i<n;i++) printf("%d ",min_val[i]);
//            return 0;
            for (int k=0;k<n;k++) numa[k] = min_val[k];//保留合并后的min_val数组
            while (!numb.empty() ) numb.pop_back();
            while (!que.empty() ) que.pop();
            while (!min_val.empty()) min_val.pop_back();
        }
        for (int k=0;k<n;k++) {
            printf("%d",numa[k]);
            if( k!= n-1 ) printf(" ");
            else printf("\n");
        }
        while (!numa.empty() ) numa.pop_back();
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值