最快洗车时间 线性dp 01背包

01背包解法:

#include <bits/stdc++.h>
using namespace std;

const int N = 100010;
int a[N],x[N],dp[N];
int n,sum;

/*
看看容量为sum/2时候选出最大的时间为多少
减去这个时间就是答案
 */
signed main()
{
    cin>>n;
    for(int i = 1 ; i <= n ; i++)
    {
        cin>>x[i];
        sum = sum + x[i];
    }
    for(int i = 1 ; i <= n ; i++ )
    {
        for(int j = sum / 2 ; j >= x[i] ; j--)
        {
            dp[j] = max(dp[j],dp[j-x[i]] + x[i]);
        }
    }
    cout<<sum - dp[sum/2]<<endl;
    return 0;
}
  • 通过固定一个洗车器花费时间为i,另一个洗车器花费时间就为sum-i
  • 枚举每一辆车在0-sum的总时间内洗和不洗两种情况(两种情况有一种情况成立即可)
    如此可以推出:dp[i][j]=dp[i-1][j] | dp[i-1][j-a[i]]
    例: 
    输出 3 1 2 3 
    dp[1][1]=dp[0][1]=true
    dp[1][2]=dp[0][2] | dp[0][2-1]=false //在只有1个的时候消耗的总时间不会超过1
    dp[2][1]=dp[1][1]=true //因为a[i]大于总消耗时间 所以只能不洗
    dp[2][3]=dp[1][3] | dp[1][3-2]=true
//本题的难点仍在于状态转移方程的设计与列写
//由于两台机器完全相同,若总时间为sum,其中一台洗车时间为i,则另一台洗车时间为sum-i
//i与sum-i中的较大值即为最终答案
//故本题可以只考虑其中一台机器,枚举其所有洗车方案(可能花费的洗车时间)并使用动态规划验证该方案是否可行
//最终遍历该台机器所有可行的洗车方案,计算并比较出最终的洗车时间 
//注:本题有一种错误解法,即把数组排序以后令两台机器分别从头和尾开始往中间遍历洗车
//这种解法是基于贪心思想的,但它并不能保证两台机器的洗车时间尽可能的接近,因此无法得出正确答案
//事实上在允许的时间复杂度内,本题并不存在直接找出最佳洗车方案的算法,
//只能使用动态规划来验证每一种洗车方案,然后比较得出最终答案 
#include <bits/stdc++.h>

using namespace std;

int Time[109];
bool dp[109][10009];
//dp[i][j]表示只考虑前i辆车(每辆车可能洗或不洗),能否使总洗车时间为j,若能则为true 

int main()
{
    int N;
    int sum=0;
    int ans=1e9;
    cin>>N;
    for(int i=1;i<=N;i++)
    {
        cin>>Time[i];
        sum=sum+Time[i];//计算总洗车时间 
    }
    
    for(int i=0;i<=N;i++)dp[i][0]=true;//初始化,若该机器总洗车时间为0,必然能做到 
     
    for(int i=1;i<=N;i++)//遍历每一种可能的洗车方案,依次考虑前1~N辆车 
    {
        for(int j=0;j<=sum;j++)//对于每一种洗车方案,遍历该机器所有可能的洗车时间,可能花0~sum分钟 
        {
            //若洗前i-1辆车的时间为j-Time[i],则洗前i辆车的时间可以是j(洗第i辆车)
            //若洗前i-1辆车的时间为j,则洗前i辆车的时间也可以是j(不洗第i辆车)
            //两种情况满足其一,dp[i][j]即为true
            //此处注意j-Time[i]要大于等于0,故分开写(合在一起写会有一个测试点错误) 
            dp[i][j]=dp[i-1][j];
            if(j>=Time[i])dp[i][j]=dp[i][j] | dp[ i - 1 ][ j - Time[i] ];    
        }    
    } 

    for(int i=1;i<=sum;i++)//遍历其中一台机器所有可能的洗车时间1~sum 
    {
        if(dp[N][i])//若对于前N辆车,该机器洗车时间可以是i 
        {
            int tmp=max(sum-i,i);//则对于该洗车方案,两台机器洗车完成的时间是sum-i和i之间的较大值 
            if(tmp<ans)ans=tmp;//比较得出所有洗车方案所花时间的最小值 
        }
    }
    cout<<ans<<endl;
    return 0;
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值