题意:
有N个任务,每个任务都花费一个单位的时间来完成,每个任务都有规定的时间期限,超出期限完成则要罚款。求所能使罚款最小的任务组合及最小罚款金额。
输入:
一个整数N代表任务个数,下面N行分别有两个整数,第一个为时间期限,第二个为超时罚款金额。
输出:
期限内完成的任务编号,期限外完成任务编号,罚款数。
本题关键在罚款金额,所以要尽可能的使罚款金额大的任务先完成,对任务根据罚款金额从大到小排序,依次处理各个任务。得到可提前完成的任务后,对任务根据时间期限排序,使期限大的任务尽可能的靠后,这样能保证提前完成的任务数量最大。
代码:
#include<iostream>#include<cstring>
using namespace std ;
typedef struct test {
int k, d, w ;
}text ;
int main(){
text tlist [100], list [100] ;
int p [100] ;
int temp[1010] ;
memset(temp, 0, sizeof(temp)) ;
int n, i, j, t ;
cin >> n ;
for(i=1; i<=n; i++){
cin >> tlist[i].d >> tlist[i].w ;
tlist[i].k = i ;
temp[tlist[i].w] ++ ;
}
for(i=2; i<=1000; i++) //计数排序
temp[i] += temp[i-1] ;
for(j=n; j>=1; j--){
list[temp[tlist[j].w]] = tlist[j] ;
temp[tlist[j].w] -- ;
}
int num = 0 ; //提前完成任务的个数
for(i=n; i>=1; i--){ //由于计数排序是从小到大排的,所以任务从大到小搜索
t = 0 ;
for(j=1; j<=num; j++)
if(list[p[j]].d<=num)
t ++ ;
if(t<list[i].d){ //若第i个任务的期限小于以确定的提前完成任务个数,将第i个加入可提前完成任务序列中
num ++ ;
p[num] = i ;
list[i].k = -list[i].k ;
j = num ;
while(j>1){ //对提前完成的任务时间期限从小到大排
if(list[p[j]].d<list[p[j-1]].d){
t = p[j] ;
p[j] = p[j-1] ;
p[j-1] = t ;
j -- ;
}
else break ;
}
}
}
for(i=1; i<=num; i++)
cout << -list[p[i]].k << " " ;
cout << endl ;
t = 0 ;
for(i=1; i<=n; i++)
if(list[i].k>0){
cout << list[i].k << " " ;
t += list[i].w ;
}
cout << endl << t ;
return 0 ;
}