A supermarket has a set Prod of products on sale. It earns a profit px for each product x in Prod sold by a deadline dx that is measured as an integral number of time units starting from the moment the sale begins. Each product takes precisely one unit of time for being sold. A selling schedule is an ordered subset of products Sell (subset of Prod) such that the selling of each product x in Sell, according to the ordering of Sell, completes before the deadline dx or just when dx expires. The profit of the selling schedule is Profit(Sell)=sum of px (x in Sell). An optimal selling schedule is a schedule with a maximum profit.
For example, consider the products Prod={a,b,c,d} with (pa,da)=(50,2), (pb,db)=(10,1), (pc,dc)=(20,2), and (pd,dd)=(30,1). The possible selling schedules are listed in table 1. For instance, the schedule Sell={d,a} shows that the selling of product d starts at time 0 and ends at time 1, while the selling of product a starts at time 1 and ends at time 2. Each of these products is sold by its deadline. Sell is the optimal schedule and its profit is 80.
tr>
schedule
|
profit
|
{a}
|
50
|
{b}
|
10
|
{c}
|
20
|
{d}
|
30
|
{b,a}
|
60
|
{a,c}
|
70
|
{c,a}
|
70
|
{b,c}
|
30
|
{d,a}
|
80
|
{d,c}
|
50
|
Write a program that reads sets of products from an input text file and computes the profit of an optimal selling schedule for each set of products.
A set of products starts with an integer 0 <= n <= 10000, which is the number of products in the set, and continues with n pairs pi di of integers, 1 <= pi <= 10000 and 1 <= di <= 10000, that designate the profit and the selling deadline of the i-th product. White spaces can occur freely in input. Input data terminate with an end of file and are guaranteed correct.
For each set of products, the program prints on the standard output the profit of an optimal selling schedule for the set. Each result is printed from the beginning of a separate line.
The sample input in contains two product sets. The first set encodes the products from table 1. The second set is for 7 products. The profit of an optimal schedule for these products is 185.
Sample Input4 50 2 10 1 20 2 30 1 7 20 1 2 1 10 3 100 2 8 2 5 20 50 10Sample Output
80 185
很容易想到的一个策略:按照时间排好序,然后依次放入,如果某一个放不进去,比较它的value与已放入的最小value,如果前者大于后者,则使它替换掉那个最小的value这样就可以用优先队列讲此题搞定。而从价值大小考虑,先按照价值从大到小排序,然后依次从起最后时刻放起,能放进去就放,放不进去就算了这是个贪心的做法,可以证明是对的按照时间从后往前放入,可以用并查集来维护,findroot(i)表示i时刻之前,与其最近的空闲时间优先队列:
#include
#include
#include
#include
#define N 10010
using namespace std;
int n;
priority_queue q;
struct CData
{
int m_nProfit;
int m_nDeadLine;
void Input()
{
scanf("%d %d",&m_nProfit,&m_nDeadLine);
}
//按照截止时间、利益的顺序排序
bool operator<(const CData b)const
{
if( m_nDeadLine != b.m_nDeadLine )
return m_nDeadLine < b.m_nDeadLine;
return m_nProfit > b.m_nProfit;
}
}p[N];
void Input()
{
for(int i = 0 ; i < n ; i++ )
{
p[i].Input();
}
}
void Solve()
{
sort(p,p+n);
int nLeft = 0; //当前剩余时间段
int nLast = 0; //当前时间
while(!q.empty()) q.pop();
for(int i = 0 ; i < n ; i++ )
{
nLeft += p[i].m_nDeadLine - nLast;
nLast = p[i].m_nDeadLine;
if( nLeft )
{
//有剩余时间,则往里面添加
nLeft--;
q.push(-p[i].m_nProfit);
}else
{
//没有剩余时间,替换掉最小的
if(!q.empty() && -q.top() < p[i].m_nProfit)
{
q.pop();
q.push(-p[i].m_nProfit);
}
}
}
int ans = 0;
while(!q.empty())
{
//最终队列里的就是答案
ans += -q.top();
q.pop();
}
printf("%d\n",ans);
}
int main()
{
while(scanf("%d",&n)==1)
{
Input();
Solve();
}
return 0;
}
并查集:
#include
#include
#include
#define N 10010
using namespace std;
struct CData
{
int m_nProfit;
int m_nDeadLine;
void Input()
{
scanf("%d %d",&m_nProfit,&m_nDeadLine);
}
bool operator<(const CData b)const
{
return m_nProfit>b.m_nProfit;
}
}p[N];
int father[N];
int findroot(int k)
{
return k==father[k]?k:father[k]=findroot(father[k]);
}
int main()
{
int n,ans,nlast;
while(scanf("%d",&n)==1)
{
nlast = 0; //最晚的截止时间
ans = 0;
for(int i = 0 ; i < n ; i++ )
{
p[i].Input();
nlast = max(nlast,p[i].m_nDeadLine);
}
sort(p,p+n); //按照利益排序
for(int i = 0 ; i <= nlast ; i++ )
{
father[i]=i; //初始化,每一个时间的最近空闲时间都是其本身
}
for(int i = 0 ; i < n ; i++ )
{
int k = findroot( p[ i ].m_nDeadLine ); //找到最近的空闲时间
if( k )
{
//如果存在最近的空闲时间,讲起塞入
ans += p[i].m_nProfit;
father[k] = findroot(k-1);
}
}
printf("%d\n",ans);
}
return 0;
}