hdu 1074 状态dp

//第一道状态dp,要理解那张图 
//要学会定义变量 
#include<iostream>
#include<string>
#include<limits.h>
using namespace std;

struct Homework{
    string name;
    int deadline;
    int costime;
};
Homework work[16];

struct DP{
    int before;
    int now;    
    int score;
    string name;
};
DP dp[65536];

void output(int end){
    if(dp[end].before==0){
        cout<<dp[end].name<<endl;
        return;
    }
    output(dp[end].before);
    cout<<dp[end].name<<endl;
}
int main(){
    int i,j,T,N;
    cin>>T;
    while(T--){
        cin>>N;
        for(i=1;i<=N;i++){
            cin>>work[i].name>>work[i].deadline>>work[i].costime;
        }
 
        dp[0].score=0;
        dp[0].now=0;
        int end=1<<N;
        for(i=1;i<end;i++){
            dp[i].score=INT_MAX;
            for(j=N-1;j>=0;j--){
                int judge=1<<j;
                if((i&judge)!=0){
                    int tmp=0;
                    if(dp[i-(i&judge)].now+work[j+1].costime-work[j+1].deadline>0)
                        tmp=dp[i-(i&judge)].now+work[j+1].costime-work[j+1].deadline;
                    if(dp[i].score>dp[i-(i&judge)].score+tmp){
                        dp[i].score=dp[i-(i&judge)].score+tmp;
                        dp[i].before=i-(i&judge);
                        dp[i].now=dp[i-(i&judge)].now+work[j+1].costime;
                        dp[i].name=work[j+1].name;
                    }
                }
            }
        }
        //======================================================================
        cout<<dp[end-1].score<<endl;
        output(end-1);
    }
    //system("pause");
    return 0;
}



hdu 1074 状态dp_第1张图片

关键要理解的是这张图,每一组数表示完成了哪些任务,比如二进制100表示只完成了第三项作业,111表示三项作业都完成了。状态转移为将能够到达的状态的某个位上的1去掉剩下的二进制序列能够转移到原状态,例如:110可能来自两个状态100 010,分别表示先完成最后一项作业和先完成第二项作业。

    状态压缩dp其实就是将状态用二进制来表示,接下来的过程就是枚举,可见枚举过程也是很重要的。该题还要注意的一点是,输出的顺序,由于需要按照字母序输出,所以按照逆序遍历的意义在于,假设前面的1已经被添加过了,先去添加后面的1。

你可能感兴趣的:(String,struct,homework,output)