HDU 1074 (状态压缩dp)详解

来源:互联网 发布:ug8.0数控编程教程 编辑:程序博客网 时间:2024/06/06 05:24

题目意思:Ignatius同学,快到期末了结果还有好多课程没有完成,每门课作业都有对应的截至日期,和完成它所需的时间,超过截至日期后,没多一天扣1分,现在文他该如何安排写作业的顺序使得被扣的分最少?

输入要求:T组数据,N门课,每门课的截至日期和完成所需的时间

输出要求:被扣的分,和写作业的顺序。(如果有不同顺序扣分相同的出现,输出字典序)

题目提示:1.因为最多只有15门课,所以1<<15在一个可以接受的范围内,但是15!太大,用枚举必定超时
2.输入时是按照字典序输入的

#include <iostream>#include <cstring>#include <stack>#include <algorithm>using namespace std;const int INF=0x3f3f3f3f;//四个3fstruct node{    string name;    int deadline;    int cost;} homework[20];struct kode{    int time;//记录时间    int score;//此时被扣的分    int pre;//它上面的一门课的编号    int now;//现在这门课的编号} dp[1<<15];int main(){    int T;    int i,j;    int s,n,end;    scanf("%d",&T);    while(T--)    {        memset(dp,0,sizeof(dp));        scanf("%d",&n);        for(i=0; i<n; i++)//建议从0开始,因为状态dp 1.....1最后一个1为2的0次方        {            cin>>homework[i].name>>homework[i].deadline>>homework[i].cost;        }        end=1<<n;        for(s=0;s<=end-1;s++)//end-1=1....1 n个1  代表所有作业已经完成了的状态 0代表没有作业完成 必须从小到大,        //后面需要利用前面求出来的temp1+dp[past].score<dp[s].score        {            int temp;//用来记录现在是选择第i门课时的状态            dp[s].score=INF;//因为要求最小值,所以刚开始把他们初始化为无限大            dp[0].score=0;//初始化,做第一门课之前时间为0;            for(i=n-1;i>=0;i--)//因为要求字典序输出,所以必须从大到小            //假设有两门课,完全相同,因为输入时是按照字典序输入的,所以开头字母大的必定序号大            //然后现进行判断,因为状态是从小往大递增的,刚开时小的已经进入,当状态大到两者都包括时,序号大的课,先进入该状态            //然后再到序号小的,而到序号小的时候因为他们截至日期和耗费时间完全一样下面的            //temp1+dp[past].score==dp[s].score因此的序号大的位置不改变,但输出时是按照状态从小到大输的,所有序号小的仍然在前面             {                temp=1<<i;//0...100...000,1距离最右边有i个数位                if(s&temp)//如果s的第i位也为0,也就是该状态下,包含第i个门课,就进入if                {                    int past=s-temp;//s-i                    //例如000011111                    //   000010000                    //  =000001111刚好就是不学第i门课时的状态                    int temp1=dp[past].time+homework[i].cost-homework[i].deadline;                    //之前的时间加上这门课需要耗费的时间                    if(temp1<0)//因为有的课会提前完成,提前完成意味着不扣分,所以为0                    {                        temp1=0;                    }                    if(temp1+dp[past].score<dp[s].score)//如果先做这门课,比之前的情况更少扣分,那么记录下来                    {                        dp[s].now=i;                        dp[s].pre=past;                        dp[s].score=dp[past].score+temp1;                        dp[s].time=dp[past].time+homework[i].cost;//记录时间                    }                }            }        }        stack<int> S;//构造一个栈        int temp2=end-1;        cout << dp[temp2].score << endl;        while(temp2)        {            S.push(dp[temp2].now);//将i门课的学习顺序以此存入栈中            temp2=dp[temp2].pre;        }        while(!S.empty())        {            cout << homework[S.top()].name << endl;//因为刚才放的时候,全部学完时的状态在最下面,最上面是s=1时,那门课的序列            S.pop();        }    }    return 0;}     
2 0
原创粉丝点击