状压dp——HDU 1074

题目含义

给出一堆课的截止时间和完成需要的时间

每完成这门课的时间超过截止时间一天就扣一分

问怎么安排完成所有课扣掉的分最少

题目分析

可以看到课总共就不超过16个 

假设有3门课,用111表示全部完成,000表示都没完成,于是这个题可以用状压dp完成

用dp[1]...dp[1<<n-1]表示n门课2^n种完成状态对应扣除的分数

用J=1<<(k-1),当J&x不为0时,表示x第k位不为0,即第K门课完成了

于是dp[x]=min(dp[x],dp[x-J]+t[x-J]+fin[j]-dea[j])

表示用你【当前的扣分】和【没完成第k门课的扣分】加上【完成k门课扣的分】取较小值

至于怎么算【完成k门课扣的分】(t[x-J]+fin[j]-dea[j])

t[i]表示在i这个二进制状态下的时间

t[i]加上完成时间,如果大于截止时间,不就超时了吗,就需要扣分

但如果没超时,你不能扣负分,就设为0

题目代码

 #include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long LL;
const int maxn=(1<<16)+7;
const int INF=0x3f3f3f3f;
int T,n;
int dea[20],fin[20],dp[maxn],pre[maxn],t[maxn];
char s[20][100];
void print(int x){
    if(x==0)return;
    print(x-(1<<pre[x]));
    printf("%s\n",s[pre[x]]);
}
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%s%d%d",&s[i],&dea[i],&fin[i]);
        int bit=1<<n;
        for(int i=1;i<bit;i++){
            dp[i]=INF;
            for(int j=n-1;j>=0;j--){
                int temp=1<<j;
                if(!(temp&i))continue;
                int score=t[i-temp]+fin[j]-dea[j];
                if(score<0)score=0;
                if(dp[i]>dp[i-temp]+score){
                    dp[i]=dp[i-temp]+score;
                    t[i]=t[i-temp]+fin[j];
                    pre[i]=j;
                }
            }
        }
        printf("%d\n",dp[bit-1]);
        print(bit-1);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/helman/p/11240961.html