poj 2442 优先队列/堆+dp
题意:
给出m行,每行n个数,每次从一行中选择一个数,这m个数求和。所有的方案数是n^m,问这些方案中和最小的n个?
分析:
这题有点桶排序和滑动窗口的意思,还是挺不错的一道题。因为要最小的n个和,所以可以用优先队列去维护最小的n个和,这n个和是第i行中的元素和前i行的和相加选择的最优的(这又有点动态规划的思想QAQ)。也就是说,前i行得到了n个最小和,那么这n个最小和可以从第i行里各选择n个数求和,一共有n^2种选择,再找出最优的n个值,重复下去。
具体的实现可以用优先队列去维护,这题划分到堆里了,还是练习一下heap吧,这题的dp思想才是关键!
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=2009; const int M=111; int a[N],sum[N],q[N],m,n; int main() { int T;scanf("%d",&T); while(T--){ scanf("%d%d",&m,&n); for(int i=0;i<n;i++)scanf("%d",&sum[i]);//边界初始化,刚开始只有一行 m--; while(m--){ for(int i=0;i<n;i++)scanf("%d",&a[i]),q[i]=sum[0]+a[i]; //q是堆,维护n个最优解 make_heap(q,q+n); for(int i=1;i<n;i++) for(int j=0;j<n;j++){ int t=sum[i]+a[j]; if(t<q[0]){ pop_heap(q,q+n); q[n-1]=t; push_heap(q,q+n); } } for(int i=0;i<n;i++)sum[i]=q[i]; } sort(sum,sum+n); for(int i=0;i<n;i++)printf("%d%c",sum[i],i==n-1?'\n':' '); } return 0; }