POJ 1337 偷懒的工人 (黑书习题)

题目描述略为坑爹,其中n取值应该为0<=n<=1000,0<=ai,di<=2500,否则在POJ上无法AC。另外1<=ti<=20这个条件可以忽略。同时ti<=di-ai<2*ti表明了一个工作只能做一次。其实题中也并没有表述工作可以在它对应的时间内重复做。。。

定义状态dp[i]表示在i时刻时,还需要工作的最少时间。由条件可以知道,每一个工作所能被做的时间段为ai~di-ti,这样便可以根据输入把每个时刻可以做的工作构成一个集合。所以对于时刻i,有dp[i] = min(dp[i],dp[i+t[k]]+t[k]);表示在i时刻做了第k个工作。如果i时刻没有工作可做,则dp[i] = dp[i+1]。边界条件为dp[maxi]=0;既所以工作的最大deadline是不可能再工作的。然后进行记忆化搜索。

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int SIZE = 1280;
int cas,n,maxi;
int t[SIZE],a[SIZE],d[SIZE];
int dp[SIZE<<1];
bool vis[SIZE<<1];
vector <int> v[SIZE<<1];

int DP(int tim)
{
    if(vis[tim])
        return dp[tim];
    if(tim >= maxi)
    {
        dp[maxi] = 0;
        return 0;
    }
    if(v[tim].size() == 0)
        dp[tim] = DP(tim+1);
    else
    {
        for(int i=0; i<(int)v[tim].size(); i++)
        {
            int to = v[tim][i];
            dp[tim] = min(dp[tim],DP(tim+t[to])+t[to]);
        }
    }
    vis[tim] = true;
    return dp[tim];
}

int main()
{
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%d",&n);
        for(int i=0; i<256; i++)
            v[i].clear();
        maxi = 0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d%d",&t[i],&a[i],&d[i]);
            for(int k=a[i]; k<=d[i]-t[i]; k++)
                v[k].push_back(i);
            if(d[i] > maxi)
                maxi = d[i];
        }
        for(int i=0; i<SIZE; i++)
            dp[i] = 0xfffffff;
        for(int i=maxi; i<SIZE; i++)
            dp[i] = 0;
        memset(vis,0,sizeof(vis));
        DP(0);
        printf("%d\n",dp[0]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值