hdu 1074 Doing Homework

链接

[https://vjudge.net/contest/256508#problem/D]

题意

就是有n门课,名称,截止日期,完成需要的时间
一旦超过截止日期一天就扣一分
问怎样安排做的顺序使得扣分最少并输出做的顺序
有相同扣分的输出字典序最小那个

分析

我是刚学状压dp,想了半天不知道怎么做就看了题解
还是学到了很多技巧,还是需要多做才有套路
很难想到的对于我来说这题
参考的思路
[https://blog.csdn.net/libin56842/article/details/24316493]
某个状态是可以有很多状态转移而来的,
思路:因为最多只有15门课程,可以使用二进制来表示所有完成的状况

例如5,二进制位101,代表第一门和第三门完成了,第二门没有完成,那么我们可以枚举1~1<<n便可以得出所有的状态

然后对于每一门而言,其状态是t = 1<<i,我们看这门在现在的状态s下是不是完成,可以通过判断s&t是否为1来得到

当得出t属于s状态的时候,我们便可以进行DP了,在DP的时候要记录路径,方便之后的输出

代码

#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<string>
using namespace std;
const int inf=0x3f3f3f3f;
struct str{
    string s;
    int d,c;
};
str a[20];
struct node{
    int endtime,last,cur,score;
    //该状态结束的时间,以及上一个状态序号一会儿方便输出,当前的课程序号,当前状态被扣的分 
}dp[1<<15];
int t,n;

int main(){
    
      //freopen("in.txt","r",stdin);
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        cin>>a[i].s>>a[i].d>>a[i].c;
        
        vector<string> ve;
        
        for(int i=1;i<(1<<n);i++)
        {
            dp[i].score=inf;
            //因为题目是字典序增的输入,你这样一会输出就是最小字典序了
            //一个小技巧吧学到了 
            for(int j=n-1;j>=0;j--)
            {   
                if(i&(1<<j)){//可能上一个状态 
                    int pre=i-(1<<j);
                    //被扣的分完成上一个的扣分 
                    int punish=dp[pre].endtime+a[j].c-a[j].d;
                     
                    if(punish<0) punish=0;
                    if(dp[i].score>dp[pre].score+punish)
                    {//更新最小扣分 
                        dp[i].score=dp[pre].score+punish;
                        dp[i].last=pre;
                        dp[i].cur=j;
                        dp[i].endtime=dp[pre].endtime+a[j].c;
                    }
                }
            }
        }
        int final=(1<<n)-1;
         printf("%d\n",dp[final].score);
        while(final){
            int tem=dp[final].cur;
            ve.push_back(a[tem].s);
            final=dp[final].last;
        }
        for(int i=ve.size()-1;i>=0;i--)
        cout<<ve[i]<<endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/mch5201314/p/10629039.html