状压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; }