这道题可以看做是一共有两个休息室,每个休息室在同一时间只能容纳一个乐师
每个乐师想要在休息室中休息一段时间,并且他们所休息的时间范围总是在乐队演出的时间范围之内。(时间范围为0~t)
不妨将所有乐师所需的休息时间的总和记作sum,根据题意可知,每个休息室中乐师休息时间的总和总是小于等于t,亦即sum<=2t,sum-t<=t
那么问题就转化为在给出的数列中寻找若干个数,使得它们的总和大于等于sum-t而小于等于t
因为数据保证方案一定存在,所以这是一定可以办到的 尝试将所有乐师所需的休息时间升序排序之后按顺序依次累加,若在累加时得到了一个大于等于sum-t而小于等于t的总和,那么问题就解决了。
若加到一个数使得当前总和大于t,则从总和之中去掉这个数以及累加的上一个数,保留这个总和再从这个数开始一个一个尝试相加
如数据为
20 8
7 5 8 4 1 9 2 3
排序之后为
1 2 3 4 5 7 8 9
此时t=20,sum = 39, sum-t=19
依次加总到7时得到了22>t,那么保留1 2 3 4,此时总和为10
10+7=17<19,不保留;
10+8=18<19,不保留;
10+9=19=19,保留,问题解决
但是我只得了64分,恳请大佬指出我思路中的错误或代码中的错误
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
int t, n, sum, book[501];
struct musician{
int want;
int time;
int num;
}m[501];
bool cmp1(musician a, musician b)
{
return a.want < b.want;
}
bool cmp2(musician a, musician b)
{
return a.num < b.num;
}
int main()
{
cin >> t >> n;
for(int i = 1; i <= n; i++)
{
cin >> m[i].want;
m[i].num = i;
sum += m[i].want;
}
int low = sum - t;
sort(m + 1, m + n + 1, cmp1);
sum = 0;
int flag = 1;
for(int i = 1; i <= n && flag; i++)
{
sum += m[i].want;
book[i] = 1;
if(low <= sum && sum <= t)
{
break;
}
if(sum < low && sum + m[i + 1].want > t)
{
sum -= m[i].want;
book[i] = 0;
for(int j = i + 1; j <= n; j++)
{
sum += m[j].want;
book[j] = 1;
if(low <= sum && sum <= t)
{
flag = 0;
break;
}
sum -= m[j].want;
book[j] = 0;
}
break;
}
}
int now = 0, now1 = 0;
for(int i = 1; i <= n; i++)
{
if(book[i])
{
m[i].time = now;
now += m[i].want;
}
else
{
m[i].time = now1;
now1 += m[i].want;
}
}
sort(m + 1, m + n + 1, cmp2);
for(int i = 1; i <= n; i++)
cout << m[i].time << ' ';
return 0;
}