您的位置:首页 > 其它

UVALive-4850 Installations

2017-10-17 20:38 281 查看
题目大意:

有若干任务, 每个任务有完成消耗的时间和截止的时间.

如果完成某个任务的时刻是t, 截止时间是d, 那么罚时就是max( 0 , t-d ), 现在求罚时最大的任务和次大的任务的罚时和最少是多少.

首先很快就可以想到一个贪心的方法: 按照时间限制d排序, 相同就按照安装时间s排序, 都从小到大, 扫一遍就可以了.

然后就会发现过不了样例.

那么我们来研究一下这个样例:

6
1 7
4 7
2 4
2 15
3 5
3 8

6个任务, 每一行前一个数是s, 表示完成消耗时间, 后一个数是d, 表示时间限制, 每个任务用Ji表示, 这个样例还有下面这个图来辅助解释:



它按照贪心的方法放的话最大和次大应该是J6和J2, 结果是8, 但是正确答案是J2和J6, 答案是7.

我们发现其实就是把J6和J2换了位置, 或者说, 是把J2放到了J6的后面.

但是只交换最大和次大明显是错的, 而把后面的放到前面来只会让大的更大, 那么我们唯一可能的方法就是把前面的放到后面来.

记一下罚时最大和次大的是哪两个任务, 然后去这两个靠后的一个的位置记为cd, 然后我们枚举cd前面的某一个移动到cd的后面, O( n )扫一遍计算答案, 更新答案, 不断移动. 再和完全不移动直接贪心的答案取min, 这样就可以得到答案了.

为什么是对的? 首先cd之后的部分是不受移动的影响的, 我们从前面取出来一个放到了cd的后面, 而在cd前面的要么截止时间靠前, 要么处理时间短, 放到cd后面只会成为新的最大值, 而旧的最大和次大其中一个会变成次大值, 就有可能会使答案变小( 答案是最大和次大的和 ).

为什么只移动一个? 因为把前面的放到cd后面, 结果变成最大, 如果再选一个绝对比原来的次大或者最大要大, 我们新增了两个更大的, 答案明显会更大, 所以只要选择一个交换.

这样复杂度就是O( n )枚举移动, O( n )计算每一种答案, 总复杂度O( n^2 ).

移动用链表实现.

代码如下:

//made by Crazy01
#include<bits/stdc++.h>
#define inf 1<<30
#define ll long long
#define db double
#define c233 cout<<"233"<<endl
#define mem(s) memset(s,0,sizeof(s))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int N=550;
using namespace std;

struct lll{
int tim,lim;
bool operator <(const lll &a)const{
return lim==a.lim?tim<a.tim:lim<a.lim;
}
}job
;
int n,T,ans,cd,r
;

inline int gi(){
int x=0,res=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
while(ch<='9'&&ch>='0')x=(x<<1)+(x<<3)+ch-48,ch=getchar();
return x*res;
}

void init(){
n=gi(); r[0]=1;
for(int i=1;i<=n;i++)
job[i].tim=gi(),job[i].lim=gi(),r[i]=i+1;
sort(job+1,job+1+n);
}

int calc(){
int t=0,max1=0,max2=0;
cd=0;
for(int i=r[0];i<=n;i=r[i]){
t+=job[i].tim;
int tle=max(0,t-job[i].lim);
if(tle>max1)max2=max1,max1=tle,cd=i;
else if(tle>max2)max2=tle,cd=i;
}
return max1+max2;
}

void work(){
if(!ans){printf("%d\n",ans); return;}
for(int i=r[0],end=cd;i<end;i=r[i]){
r[i-1]=r[i]; r[i]=r[end]; r[end]=i;
ans=min(ans,calc());
r[end]=r[i]; r[i]=r[i-1]; r[i-1]=i;
}
printf("%d\n",ans);
}

int main(){
T=gi();
while(T--){
mem(job);
init();
ans=calc();
work();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: