首页 > 代码库 > hdu 1074 Doing Homework(状压DP)

hdu 1074 Doing Homework(状压DP)

题意:

有N(N<=15)个作业,每个作业有个名字、上交截止时间、完成它所耗的时间。

一个作业每超期一天扣一分。

问小余如何安排做作业的顺序,才能使扣的分最少。

输出最少扣分,安排的顺序。

 

思路:

总共有N!个安排方案。暴力超时。所以想到用DP。

如何表示状态?N小于等于15,可以用状态压缩。

具体,,,,看代码吧,,

这里用前一个状态推导后一个状态的方式,这样好写。 

 

代码:

struct node{    char name[105];    int deadline, days;}work[20];int n;int cn=0;int ds[36005];int dp[36005];int path[36005];void dfsCalc(int lastPos,int totalNum,int Num){ //正要打算从n个中选totalNum个,当前状态为Num    if(totalNum<=0){        ds[++cn]=Num;        return;    }    rep(i,lastPos+1,n-totalNum+1){        int NUM=Num+(1<<(i-1));        dfsCalc(i,totalNum-1,NUM);    }}int calcState(int state){    int ans=0;    rep(i,0,n-1){        int t=(state&(1<<i));        if(t!=0){            ans+=(work[i+1].days);        }    }    return ans;}bool cmp(node a,node b){    return strcmp(a.name,b.name)<0;}int main(){    int T;    cin>>T;    while(T--){        scanf("%d",&n);        rep(i,1,n){            scanf("%s%d%d",work[i].name,&work[i].deadline,&work[i].days);        }        sort(work+1,work+1+n,cmp);        mem(dp,inf);        rep(i,1,n){            int state=(1<<(i-1));            if(work[i].days>work[i].deadline){                dp[state]=work[i].days-work[i].deadline;                path[state]=i;            }else{                dp[state]=0;                path[state]=i;            }        }        rep(i,1,n-1){            cn=0;            dfsCalc(0,i,0);            rep(j,1,cn){                int oldState=ds[j];                rep(k,1,n){                    if((oldState&(1<<(k-1)))==0){                        int newState=oldState+(1<<(k-1));                        int temp=calcState(oldState);                        if(temp+work[k].days>work[k].deadline){                            if( dp[oldState]+temp+work[k].days-work[k].deadline<dp[newState] ){                                dp[newState]=dp[oldState]+temp+work[k].days-work[k].deadline;                                path[newState]=k;                            }                        }else{                            if( dp[oldState]<dp[newState] ){                                dp[newState]=dp[oldState];                                path[newState]=k;                            }                        }                    }                }            }        }        int N=(1<<n)-1;        printf("%d\n",dp[N]);        int ansPath[15];        int ansNum=0;        while(N){                ansPath[++ansNum]=path[N];                N-=(1<<(path[N]-1));        }        rep2(i,ansNum,1){            puts(work[ansPath[i]].name);        }    }    return 0;}

 

hdu 1074 Doing Homework(状压DP)