HNOI2001 产品加工

[HNOI2001] 产品加工

题目描述

某加工厂有 A、B 两台机器,来加工的产品可以由其中任何一台机器完成,或者两台机器共同完成。由于受到机器性能和产品特性的限制,不同的机器加工同一产品所需的时间会不同,若同时由两台机器共同进行加工,所完成任务又会不同。

某一天,加工厂接到 \(n\) 个产品加工的任务,每个任务的工作量不尽一样。

你的任务就是:已知每个任务在 A 机器上加工所需的时间 \(t_1\),B 机器上加工所需的时间 \(t_2\) 及由两台机器共同加工所需的时间 \(t_3\),请你合理安排任务的调度顺序,使完成所有 \(n\) 个任务的总时间最少。

输入格式

第一行为一个整数 \(n\)

接下来 \(n\) 行,每行三个非负整数 \(t_1,t_2,t_3\),分别表示第 \(i\) 个任务在 A 机器上加工、B 机器上加工、两台机器共同加工所需要的时间。如果所给的时间 \(t_1\)\(t_2\)\(0\) 表示任务不能在该台机器上加工,如果 \(t_3\)\(0\) 表示任务不能同时由两台机器加工。

输出格式

仅一行一个整数,表示完成所有 \(n\) 个任务的最少总时间。

样例 #1

样例输入 #1

5                            
2 1 0
0 5 0
2 4 1
0 0 3
2 1 1

样例输出 #1

9

提示

对于所有数据,有 \(1\le n\le 6\times 10^3\)\(0\le t_1,t_2,t_3\le 5\)

神奇抽象dp题:记dp[i][j]为完成第i个,A最后用时为j,B的最小用时

显然有三种状态转移:
让A做:dp[i-1][j-t1[i]]
让B做:dp[i-1][j]+t2[i]
让AB做 :dp[i-1][j-t3[i]]+t3[i]
``
但是对于125MB的空间限制,我们显然开不出nnk的数组,我们观察状态转移方程可以发现,dp[i]只能从dp[i-1]转移来,我们可以用滚动数组优化掉

但是对于n个物品,最大容量为 \(n\times5\) 的背包,我们显然不能 \(n\times n\times5\)转移。我们发现有很多转移到背包是空的,每次转移到时候我们只需要在一个范围[L,R]内进行转移

至于L,R的计算:

对于每次转移:
R+=max(t1,t3)
L+=t1 or t3

Code:

const int N=6005;
const int inf=1e9;
using namespace std;
int dp[N*5],t1[N],t2[N],t3[N];
int n,L,R;
void init()
{
    for(int i=0;i<N*5;i++){dp[i]=inf;}
}
void work()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&t1[i],&t2[i],&t3[i]);
    }
    init();
    dp[0]=0;
    for(int i=1;i<=n;i++)
    {
        R+=max(t1[i],t3[i]);
        for(int j=R,A,B,AB;j>=L;j--)
        {
            A = (t1[i] ? (j-t1[i]>=0 ? dp[j-t1[i]] : inf) : inf);
            B = (t2[i] ? dp[j]+t2[i] : inf);
            AB= (t3[i] ? (j-t3[i]>=0 ? dp[j-t3[i]]+t3[i] : inf) : inf);
            dp[j]=min(AB,min(A,B));
        }
        L+=(t2[i]|t3[i] ? 0 : t1[i]);
        L+=(t1[i]|t2[i] ? 0 : t3[i]);
    }
    int ans=inf;
    for(int i=0;i<=n*5;i++)
    {
        ans=min(ans,max(i,dp[i]));
    }
    printf("%d\n",ans);
}
int main()
{
    //freopen("P2224.in","r",stdin);freopen("P2224.out","w",stdout);
    work();
    return 0;
}`
posted @ 2024-10-08 23:03  liuboom  阅读(20)  评论(0)    收藏  举报