您的位置:首页 > 其它

uva11997 K Smallest Sums(优先队列)

2015-08-03 11:31 405 查看
题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18702

题意:N行N列矩阵,每行选一个数求和,选出前N个最小的和。

代码:

/*
简化问题: 
a和b两个序列都有n个元素,从a何b中各选一个元素求和,有n*n种情况,找出
前n小的n个和。

考虑所有情况: 
a[1]+b[1]	a[1]+b[2]	a[1]+b[3]	a[1]+b[4] 。。。
a[2]+b[1]	a[2]+b[2]	a[2]+b[3]	a[2]+b[4]。。。
a[3]+b[1]	a[3]+b[2]	a[3]+b[3]	a[3]+b[4]。。。
a[4]+b[1]	a[4]+b[2]	a[4]+b[3]	a[4]+b[4]。。。
。。。。。

分析:
若将b[]从小到大排序,那么最小的和就应该在第一列。
然后将最小的那个值选出,值后面的n-1个值向前移位,
那么,最小的和还应该在第一列。 

解决:
用优先队列维护第一列的值就行了。

扩展:n路合并 

*/

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
struct node
{
	int s,p;
	node(int a=0,int b=0)
	:s(a),p(b){}
	bool operator < (const node &t)const
	{
		return s>t.s;
	}
};
priority_queue <node > q;
int N,f[1000],t[1000];

void Merge(int a[],int b[])
{
	while(!q.empty())
		q.pop();
	for(int i=0;i<N;i++)
		q.push(node(a[i]+b[0],0));
	node temp;
	for(int i=0;i<N;i++)
	{
		temp=q.top();
		q.pop();
		a[i]=temp.s;
		if(temp.p+1<N)
			q.push(node(temp.s-b[temp.p]+b[temp.p+1],temp.p+1));
	}
}

int main()
{
	int i,j;
	while(scanf("%d",&N)!=EOF)
	{
		for(i=0;i<N;i++)
			scanf("%d",&f[i]);
		for(i=1;i<N;i++)
		{
			for(j=0;j<N;j++)
				scanf("%d",&t[j]);
			sort(t,t+N);
			Merge(f,t);
		}
		printf("%d",f[0]);
		for(i=1;i<N;i++)
			printf(" %d",f[i]);
		printf("\n");
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: