[雅礼中学2005分区联赛模拟试题]工作
[题目]
工作(Work.pas/exe)
【题目描述】
这次故事的主角是HG!转眼4年过去了,HG本科毕业了,于是找了份工作。每天HG会收到一份任务清单,清单上列出了n个可能需要他完成的任务。每个任务包含3个信息:Ti、Ai、Bi,Ti表示完成此任务需要的时间,Ai表示此任务的到达时间,Bi表示此任务的最晚完成时间。在某一时刻若HG手上没有任务,那么他可以选择一个已经到达且还能够在Bi时刻之前(或者恰好在Bi时刻)完成的任务来做。
由于HG有点懒(纯属虚构:D),他想尽量少的减少他的总工作时间,但是他不能在可以做任务的时候故意不做(这样会被炒鱿鱼的>_<),那么他该如何挑选任务来做呢?
你的任务就是求出HG的最少工作时间(即总共有多少时间HG在做任务)。
【输入】
第一行一个整数n表示任务数。
以下n行,每行三个整数Ti,Ai,Bi。(n<=1000,0<=Ai,Bi<=1500,Ti>=1)
【输出】
输出仅一个数,即最少工作时间。
【样例输入】
3
15 0 25
50 0 90
45 15 70
【样例输出】
50
【数据范围】
Ti>=1,0<=Ai,Bi<=1200;
30%的数据满足n<=5;
60%的数据满足n<=500;
100%的数据满足n<=1000。
【说明】
输入数据保证Bi-Ai要大于等于Ti,且小于2Ti。
[成绩]
标题:工作 | |||
文件名:work.cpp | |||
编号 | 结果 | 得分 | 有效用时 |
1 | 正确 | 10 | 0.03 |
2 | 正确 | 10 | 0.01 |
3 | 正确 | 10 | 0.01 |
4 | 正确 | 10 | 0.01 |
5 | 正确 | 10 | 0.01 |
6 | 正确 | 10 | 0.01 |
7 | 正确 | 10 | 0.03 |
8 | 正确 | 10 | 0.03 |
9 | 正确 | 10 | 0.03 |
10 | 正确 | 10 | 0.03 |
总分:100 | |||
有效用时:0.20 |
[报告]
这个其实就是DP——虽然我考试的时候写了个SEARCH。
F[I]表示直到第I时刻前(包括第I时刻)最少工作时间。
则F[I]=MIN{F[I-1] (若I-1时刻没工作好干)
F[I-t[K]]+t[K] (若I-t[K]时刻开始干第K项工作能够完成)}
对于方程的第一行,不用解释,对吧。
对于第二行,由于题目保证t[i]<=A[I]-B[I]<=2*t[i],所以每项工作不可能干两次,这个保证了方程第二项的正确性。
至此,这题也圆满解决——该做法也是标程的做法。
[程序]
// DP
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#define N 1000
#define T 2000
using namespace std;
ifstream fin ("work.in");
ofstream fout ("work.out");
long a[N+1],b[N+1],t[N+1];
long n;
long f[T+1];
int main(int argc, char *argv[])
{
fin >> n;
for (long i=1;i<=n;i++)
fin
>> t[i]
>> a[i]
>> b[i];
memset(f,42,sizeof(f));
f[0]=0;
for (long i=0;i<=T;i++)
{
bool flag=true;
for (long
j=1;j<=n;j++)
if
(i>=a[j]&&i+t[j]<=b[j])
{
flag=false;
if
(f[i+t[j]]>f[i]+t[j])
f[i+t[j]]=f[i]+t[j];
if
(flag&&f[i+1]>f[i])
f[i+1]=f[i];
fout << f[T]
<< endl;
return
EXIT_SUCCESS;
}
// 搜索
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#define N 1000
#define T 2000
using namespace std;
ifstream fin ("work.in");
ofstream fout ("work.out");
long a[N+1],b[N+1],t[N+1];
long n,ans;
static inline void
swap(long&a,long&b)
{
long t=a;a=b;b=t;
}
static inline bool xxx(long a1,long b1,long t1,long a2,long b2,long
t2)
{
if (a1<a2) return true;
else if (a1>a2) return
false;
else if (b1<b2) return true;
else if (b1>b2) return
false;
else return (t1<t2);
}
static inline void quick(long bb,long ee)
{
long i=bb,j=ee,k=rand()%(ee-bb+1)+bb;
long xa=a[k],xb=b[k],xt=t[k];
while (i<=j)
{
while
(xxx(a[i],b[i],t[i],xa,xb,xt)) i++;
while
(xxx(xa,xb,xt,a[j],b[j],t[j])) j--;
if (i<=j)
{
swap(a[i],a[j]);
swap(b[i],b[j]);
swap(t[i],t[j]);
i++,j--;
}
}
if (bb<j) quick(bb,j);
if (i<ee) quick(i,ee);
}
static inline long min(long a,long b)
{
return ((a<b)?a:b);
}
static inline long max(long a,long b)
{
return ((a>b)?a:b);
}
static inline bool cross(long x1,long x2,long y1,long y2)
{
return
(!((x2<y1)||(x1>y2)));
}
class CALC
{
public:
long bi,ei,bx,ex;
long ans;
inline void solve(long dex,long
ti)
{
if
(dex>=ex)
{
if
(ti<ans) ans=ti;
return;
}
if
(ti>=ans)
return;
// 上下界剪枝
bool
flag=false;
while
(!flag)
{
flag=false;
for
(long i=bi;i<=ei;i++)
if
(dex>=a[i]&&dex+t[i]<=b[i])
// 现在开始能完成任务
{
flag=true;
solve(dex+t[i],ti+t[i]);
}
if
(!flag)
// 若当前无法安排任务
if
(dex<ex)
dex++;
// 搜索下一个时间点
else
{solve(dex,ti);break;}
else
break;
}