状压dp Doing Homework

来源:互联网 发布:cms快速建站与运营 编辑:程序博客网 时间:2024/06/10 22:19

题目地址

题目大意:

T组样例,N科作业,接下来N行,每行包括作业名称(字典序排列),截至时间,消耗时间,

每门作业,晚完成每分钟减一分,输出做少罚分与对应字典序小的做作业顺序

思路:

对于每门课建一个map给予编号t ,1<<t表示完成,由于输出时要输出科目顺序,所以需要记录最小值的前一门作业,时间和分数和当前科目

就是给dp数组建成结构体,过程比较简单

代码:

#include<iostream>#include<stdio.h>#include<algorithm>#include<string.h>#include<math.h>#include<queue>#include<stack>#include<map>using namespace std;stack<int>S;map<int,string>m;int N,T,c[16],v[16];struct AA{    int fname,grade,time,n;}dp[1<<17];char ch[100];int main(){    int i,j,k,a,b;   cin>>T;   while(T--)   {       memset(dp,0,sizeof(dp));       scanf("%d",&N);       for(i=0;i<N;i++)        {            scanf("%s%d%d",ch,&c[i],&v[i]);            m[i]=ch;        }        for(i=1;i<(1<<N);i++)        {            dp[i].grade=0x3f3f3f3f;            for(j=N-1;j>=0;j--)//从后到前更新,满足字典序            {                if(i&1<<j)//i的第j-1门课做了                {                    int z=i-(1<<j);//除去第j-1门课                    if(dp[i].grade>dp[z].grade+max(0,dp[z].time+v[j]-c[j]))//每门课最少扣0分,找最优解                    {                        dp[i].grade=dp[z].grade+max(dp[z].time+v[j]-c[j],0);                        dp[i].fname=z;//前一个状态                        dp[i].n=j;//刚添加的课程                        dp[i].time=dp[z].time+v[j];                    }                }            }        }        int l=(1<<N)-1;        cout<<dp[l].grade<<endl;        while(l)        {            S.push(dp[l].n);//从末状态,按最佳路径推回到初状态            l=dp[l].fname;        }        while(!S.empty())        {            cout<<m[S.top()]<<endl;            S.pop();        }   }}