POJ-1949(模拟或DP)

36 篇文章 0 订阅
18 篇文章 0 订阅

一、很容易想到如下的模拟过程:

(0)使没有先决条件的工作进入服务窗口

(1)找到所有正在处理的工作中剩余所需时间最少的工作所需的时间T

(2)将所有窗口剩余所需时间减去T,如果该窗口的工作已经完成,则将其当做先决条件的工作所需的先决条件的数量减一,如果这一工作已经没有任何先决条件,则将其送入一个窗口开始进行服务

(3)如果所有窗口都已经没有在进行服务,则过程停止

根据以上步骤,很容易写出模拟代码:


#include <cstdio>
#include <vector>
#include <list>
using namespace std;
#define MAX 10001

struct Job{
    int timeNeeded;
    int numberOfPrerequisites;
    vector<int> nextJobs;
} arr[MAX];
int N;

int getLeastTimeNeeded(const list<int>& jobList)
{
    list<int>::const_iterator iter = jobList.begin(), eter = jobList.end();
    int t = arr[*iter++].timeNeeded, i;
    for(; iter != eter; ++iter){
        i = *iter;
        if(t > arr[i].timeNeeded) t = arr[i].timeNeeded;
    }
    return t;
}
void insertSubsequentJobs(list<int>& jobList, int doneID)
{
    if(arr[doneID].nextJobs.empty()) return;
    for(int i = 0, n = arr[doneID].nextJobs.size(); i < n; ++i){
        int j = arr[doneID].nextJobs[i];
        if(--arr[j].numberOfPrerequisites == 0) jobList.push_front(j);
    }
}

int main()
{
//step 1: input job count
    scanf("%d", &N);
//step 2: input job graph
    int i, j, k;
    for(i = 1; i <= N; ++i){
        scanf("%d %d", &arr[i].timeNeeded, &arr[i].numberOfPrerequisites);
        for(j = 0; j < arr[i].numberOfPrerequisites; ++j){
            scanf("%d", &k);
            arr[k].nextJobs.push_back(i);
        }
    }
//step 3: initialize job line
    list<int> jobList;
    list<int>::iterator iter, eter;
    for(i = 1; i <= N; ++i){
        if(arr[i].numberOfPrerequisites == 0) jobList.push_front(i);
    }
//step 4: schedule jobs
    int totalTime = 0, time;
    while(!jobList.empty()){
        //find out the job which need least time now
        totalTime += time = getLeastTimeNeeded(jobList);
        //minus each job with time
        for(iter = jobList.begin(), eter = jobList.end(); iter != eter; ){
            i = *iter;
            arr[i].timeNeeded -= time;
            if(arr[i].timeNeeded == 0){
                iter = jobList.erase(iter);
                insertSubsequentJobs(jobList, i);
            }
            else ++iter;
        }
    }
//step 5: print result
    printf("%d", totalTime);

    return 0;
}
二、实际上此题还可以看做树型DP的问题,把每一个工作看成一个节点,将先决条件看成其子节点,则dp[parent] = max{dp[children] + costOfParent},并且题中" Farmer John's list of chores is nicely ordered, and chore K (K > 1) can have only chores 1,.K-1 as prerequisites." 说明我们可以边读入边DP而不用保存节点信息:


#include <cstdio>
#define MAX 10001

int N, dp[MAX] = {0};

int main()
{
    scanf("%d", &N);
    int i, j, k, n, t, ans = 0;
    for(i = 1; i <= N; ++i){
        scanf("%d %d", &t, &n);
        if(n == 0) dp[i] = t;
        else{
            for(j = 0; j < n; ++j){
                scanf("%d", &k);
                if(dp[k] + t > dp[i]) dp[i] = dp[k] + t;
            }
        }
        if(dp[i] > ans) ans = dp[i];
    }
    printf("%d", ans);

    return 0;
}

从时间上来看,用了DP之后,速度并没有得到质的改变,目测是因为数据量太大,大部分时间消耗在了scanf上:

当大部分时间用在IO上时,改进算法的作用微乎其微



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值