woj1208 Sherlock's Code

来源:互联网 发布:ubuntu 安装 uefi启动 编辑:程序博客网 时间:2024/05/20 13:12

题目链接:

http://acm.whu.edu.cn/learn/problem/detail?problem_id=1208

题目的大概意思是输入两个长度为N的数组,计算数组的两两之和,得到N*N个数后,从小到大排序,输出前N个数。

题目的限制条件还是有的,数据的规模:数组的长度1 <= N <= 50000;空间限制:65536KB;时间限制是1s.

这道题卡了我很久。拿到题的第一想法就是,肯定不能直接按照题目的意思去做,因为这样做内存很容易超。需要另辟思路,第一个想法是用一个规模为N的堆(大根堆)去维护输出的结果。遍历计算,每次得到一个和值,就与堆顶的元素相比较,如果该和值比堆顶元素小,就将堆顶元素出堆,将该元素入堆,重新调整堆。当所有元素遍历完以后,再对这个大根堆进行一次排序,然后输出即可。

#include<iostream>#include<stdio.h>#include<algorithm>#include<vector>using namespace std;int main(){freopen("in.txt","r",stdin);int n;while(cin>>n){vector<int> va,vb,vheap;int temp;for(int i=0;i<n;++i){cin>>temp;va.push_back(temp);}for(int i=0;i<n;++i){cin>>temp;vb.push_back(temp);}for(int i=0;i<n;++i)//初始化堆 {temp=va[0]+vb[i];vheap.push_back(temp);}make_heap(vheap.begin(),vheap.end()); for(int i=1;i<n;++i){for(int j=0;j<n;++j){int temp=va[i]+vb[j];if(temp<vheap[0])//小于堆顶元素则重新调整堆{vheap.erase(vheap.begin());//删除堆顶元素vheap.push_back(temp);//temp入堆make_heap(vheap.begin(),vheap.end());}}}sort_heap(vheap.begin(),vheap.end());cout<<vheap[0];for(int i=1;i<n;++i)cout<<" "<<vheap[i];cout<<endl;va.clear();vb.clear();vheap.clear();}return 0;}

上面的算法复杂度还是比较高的,O(n2logn),提交超时也正常。还是沿着这种思路,稍微优化修改一下就行了。上面的代码比较粗糙。

这题的优化解法可以参考《算法导论》中k路归并算法,可以这样考虑,将a[n]和b[n]排序后,用b[n]中的每个元素去加a[n]中的一个元素,得到n个有序表,再把这n个有序表合并成一个有序表即可。

得到的n个有序表如下:

a[0]+b[0]<= a[0]+b[1]<= a[0]+b[2]<=…<=a[0]+b[n-1];

a[1]+b[0]<= a[1]+b[1]<= a[1]+b[2]<=…<=a[1]+b[n-1];

a[n-1]+b[0]<= a[n-1]+b[1]<= a[n-1]+b[2]<=…<=a[n-1]+b[n-1].

归并时,可以这样考虑,每个表的元素按序移入一个新表中,把每个表的当前元素放入一个二叉堆中,每次删除最小值并放入新表中,然后加入此序列的下一个元素,直到n个表遍历完。这种算法每次耗时log(n),n次共耗时nlog(n),所以AC掉这题是没有问题的。

具体的实现就是:读入a[n]和b[n],并将其升序排序,再将第一个有序表a[0] + b[i] ( 0<=i<=n-1)读入q向量中,维护一个大小为n的二叉堆。然后考虑第1个有序表,b[1] + a[i] (0<=i<=n-1),如果b[1] + a[i]比堆q的堆顶元素大,则退出,否则删除堆的堆顶元素,插入b[1] + a[i],依次计算其他有序表即可。再q的数据拷贝到a中,并对a按升序排序,输出a中的数据即可。

AC代码如下:

#include <iostream>#include <stdio.h>#include <queue>#include <algorithm>using namespace std;  const int N=50000;int main()  {    freopen("in.txt","r",stdin);    int n;    int num1[N];    int num2[N];    priority_queue<int,deque<int>,less<int> > big;    while(scanf("%d",&n)!=EOF)    {         for(int i=0;i<n;i++)          scanf("%d",&num1[i]);          sort(num1,num1+n);        for(int j=0;j<n;j++)          {              scanf("%d",&num2[j]);              big.push(num1[0]+num2[j]);          }          sort(num2,num2+n);          for(int k=1;k<n;k++)             for(int l=0;l<n;l++)              {                  if(num1[k]+num2[l]>big.top())                      break;                      big.pop();                      big.push(num1[k]+num2[l]);              }         for(int k=0;k<n;k++)          {              num1[n-k-1]=big.top();              big.pop();          }        printf("%d",num1[0]);          for(int i=1;i<n;i++)              printf(" %d",num1[i]);//printf("\n");    }    return 0;}
1 0
原创粉丝点击