[HDU] 1789 Doing Homework again
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1789
方法:
既然一个作业超期了,不管超期多久都只扣一次固定的学分。又因为每个作业只要一天,所以可以看出n个作业n天就可以做完,那些截至日期大于n天的就不用考虑了。只考虑截至日期在n天内的。可以这样考虑,设截至日期在n天内的作业如果全部按时完成的话得到的学分的和是sum,再设一个实际获得学分t_sum(初始0),然后一个作业按时完成 t_sum就加上学分,超期的就不管,然后把原来的问题转变为在截至日期在n天内的作业中安排一个顺序使得获得的学分之和t_sum最大,然后用sum-t_sum得到扣除的最少学分,这样得到原来问题的解。
设D[i]为一个截至日期,D[i].values截至日期是D[i]的作业有哪些,然后从第一天开始计算,计算第D[i]前必须做完的作业中选择D[i]个作业来做能获得的最大学分,计算过程为,首先计算截止期是第一天的作业,从D[1].values选择出最高学分那个,当然只选1个,然后把它并入D[2].values,再选出2个最高学分的作业,然后再将这两个并入D[3].values,再选出3个最高分的哪个。。。。最后在D[n].values中选择最高分的n个作业,将学分相加得到t_sum。
问题解决了。
代码:
#include <iostream>
#include <queue>
using namespace std;
int n;
struct Course
{
int deadLine;
int get;
};
struct DeadLine
{
priority_queue<int> values;
};
Course courses[1001];
DeadLine deadlines[1001];
int main()
{
int tc=0;
scanf("%d",&tc);
while(tc>0)
{
scanf("%d",&n);
int sum = 0;
for(int i =1;i<=n;i++)
scanf("%d",&courses[i].deadLine);
for(int i =1;i<=n;i++)
scanf("%d",&courses[i].get);
priority_queue<int> no_values ;
for(int i =1;i<=1000;i++)
deadlines[courses[i].deadLine].values = no_values;
for(int i =1;i<=n;i++)
{
if(courses[i].deadLine<=n)
{
sum+=courses[i].get;
deadlines[courses[i].deadLine].values.push(courses[i].get);
}
}
int re =0;
for(int i=1;i<=n;i++)
{
int t_re = 0;
priority_queue<int> t_values = deadlines[i].values;
if(!deadlines[i].values.empty())
{
int j=0;
while(j<i && !deadlines[i].values.empty())
{
t_re+=deadlines[i].values.top();
deadlines[i].values.pop();
j++;
}
}
re = re>t_re ?re :t_re;
bool foundOne =false;
int k=i;
while(k<n)
{
if(!deadlines[k+1].values.empty())
{
foundOne =true;
break;
}
k++;
}
if(foundOne)
{
int j=0;
deadlines[i].values = t_values;
while(j<i && !deadlines[i].values.empty())
{
deadlines[k+1].values.push(deadlines[i].values.top());
deadlines[i].values.pop();
j++;
}
i=k;
}
}
cout<<sum-re<<endl;
tc--;
}
return 0;
}
感想:模拟,注意代码中基于概率优化的部分
浙公网安备 33010602011771号