题意
主角打完ACM比赛回来,有一堆作业要做,每个作业有自己的deadline和score,如果不能在deadline之前完成就拿不到这个作业的分数,问主角最多能拿多少分
思路
按日期从小到大排,如果日期相同则按罚分从大到小排 按日期遍历,对应天数做对应期限的作业,如果期限重复了,就查找这一天之前的罚分最少的作业(回溯),如果这一天之前罚分最少的作业的罚分都比这一天作业的罚分大,则这一天就甘愿被罚掉。这一天就老老实实的做这个作业,然后再往后走
样例
Sample Input
3
3
3 3 3
10 5 1
3
1 3 1
6 2 3
7
1 4 6 4 2 4 3
3 2 1 7 6 5 4
Sample Output
0
3
5
AC代码
#include <iostream>
#include <algorithm>
using namespace std;
struct S
{
int deadline;
int reduce;
};
S x[1002];
bool cmp(S a, S b)
{
if(a.deadline==b.deadline)
return a.reduce>b.reduce;
return a.deadline<b.deadline;
}
int main()
{
int t,n,j;
int vis[1002];
cin>>t;
while(t--)
{
cin>>n;
memset(vis,0,sizeof(vis)); //vis每次初始化,并且要用这种方式来初始化,用“int vis[1002];”也不管
for(int i=1;i<=n;i++)
cin>>x[i].deadline;
for(int i=1;i<=n;i++)
cin>>x[i].reduce;
sort(x, x + n+1, cmp);
/* //检测排序结果
cout<<endl;
for(int i=1;i<=n;i++)
{
cout<<x[i].deadline<<" ";
}
cout<<endl;
for(int i=1;i<=n;i++)
{
cout<<x[i].reduce<<" ";
}
cout<<endl<<endl;
*/
int day=1,sum=0; //这两个个参数要每一次都重置,否则结果不对。注意,vis在此重新定义的话好像不管用,OJ报“Wrong answer”.就拿到前面“memset(vis,0,sizeof(vis));”来初始化了
for(int i=1;i<=n;i++)
{
if(day<=x[i].deadline) //对应天数做对应期限的作业.在这里原本直接用的i来替代day的作用,但结果一直不对
{
day++;
vis[i]=1; //对已确定的作业做标记
}
else
{
int mix=x[i].reduce;
int flag;
for(j=1;j<=i-1;j++) //查找这一天之前的罚分最少的作业
{
if(vis[j]==1 && x[j].reduce<mix)
{
mix=x[j].reduce;
flag=j;
}
}
if(mix<x[i].reduce)
//前面罚分最小的作业比当前的作业小,则交换,找到了替死鬼
{
S xx=x[flag];
x[flag]=x[i];
x[i]=xx;
i--; //回退一个
}
else
//前面罚分最小的作业比当前的作业大,则当前作业甘愿被罚
{
sum+=x[i].reduce; //累计罚分
}
}
}
cout<<sum<<endl;
}
}
题源:acm.hdu.edu.cn/showproblem…