work 工作 (dp)

【work题解】

10.16

思路:
dp(i,j,k)考虑了前i件事,同时距离i最近的j件事的状态,k表示最近的做的事距离i的距离。
每次决策只有两种,先取出之间没做的某件事v做了,即
dp[i][j | (1 << v)][v] = min(dp[i][j | (1 << v)][v], dp[i][j][k] + ( (k == 19) ? a[i - v] : calc(a[i - v] , a[i - k] ) ) )
将第i件事压下暂时不做,即
dp[i + 1][(j^(1<<7))<<1][min(k + 1, 19)] =min(dp[i + 1][(j^(1<<7))<<1][min(k + 1, 19)], dp[i][j][k])
显然这两种转移已经包含了所有情况。
复杂度O(n∗28∗162)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 1050
using namespace std;

const int inf = 0x7f7f7f7f;

int n; 
int a[N], b[N], dp[N][1 << 8][17] ;

inline int cal ( int x , int y ){ return (x | y) - (x & y); }

int main(){
    freopen("work.in", "r", stdin);
    freopen("work.out", "w", stdout);
    scanf("%d", &n);
    for(int i=1; i<=n; ++i) scanf("%d%d", &a[i], &b[i]);
    memset( dp , 0x7f , sizeof( dp ) );
    dp[0][(1 << 8)-1][16] = 0;
    for(int i=0; i<=n; ++i)
        for(int j=0; j<(1 << 8); ++j)
            for(int k=0; k<17; ++k)
                if( dp[i][j][k] != inf ){
                    int ed = min(i , 8), limit = inf;
                    for(int v=ed-1; v>=0; --v) 
                        if( (( j >> v) & 1) == 0 )//只能先做这些没做的事的b以内的事件 
                            limit = min( limit, i - v + b[i-v] );
                    if( (j >> 7 & 1) == 1 ) //将第i件事压下暂时不做(保证先把下一步就做不了的事做了)
                        dp[i+1][(j^(1<<7))<<1][min(k+1, 16)] = min(dp[i+1][(j^(1<<7))<<1][min(k+1, 16)], dp[i][j][k]);
                    for(int v=ed-1; v>=0 && i-v<=limit; --v) 
                        if( (j >> v & 1) == 0 )//先取出之间没做的某件事v
                            dp[i][j|(1<<v)][v] = min(dp[i][j|(1<<v)][v], dp[i][j][k]+((k==16)?a[i-v]:cal(a[i-v], a[i-k])));
                }
    int ans = inf;
    for(int i=0; i<17; ++i) ans = min( ans, dp[n][(1<<8)-1][i] );
    printf("%d\n" , ans );
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值