当前位置: 代码迷 >> 综合 >> hdu - 1074(超级详细)
  详细解决方案

hdu - 1074(超级详细)

热度:21   发布时间:2023-11-17 11:11:10.0

看了半天题解,感觉这道题好神奇,这种方法枚举真厉害!!

题目:点此进入

Doing Homework

Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Every teacher gives him a deadline of handing in the homework. If Ignatius hands in the homework after the deadline, the teacher will reduce his score of the final test, 1 day for 1 point. And as you know, doing homework always takes a long time. So Ignatius wants you to help him to arrange the order of doing homework to minimize the reduced score.

Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case start with a positive integer N(1<=N<=15) which indicate the number of homework. Then N lines follow. Each line contains a string S(the subject’s name, each string will at most has 100 characters) and two integers D(the deadline of the subject), C(how many days will it take Ignatius to finish this subject’s homework).

Note: All the subject names are given in the alphabet increasing order. So you may process the problem much easier.

Output
For each test case, you should output the smallest total reduced score, then give out the order of the subjects, one subject in a line. If there are more than one orders, you should output the alphabet smallest one.

Sample Input
2
3
Computer 3 3
English 20 1
Math 3 2
3
Computer 3 3
English 6 3
Math 6 3

Sample Output
2
Computer
Math
English
3
Computer
English
Math

这道题初看时完全懵逼,只知道是DP(应为我们学校再刷DP专题,反正咋想也没有思路,就去百度了,一看压缩。。就。。啥也不想说,看了一天估计因为没做过不敢看也没看懂,第二天再看时,互然就看明白了,不多说废话了,解释题


题目大意:就是快要交作业了,有N门课,课还有D天就要交,他需要写C天,超过期限还没写完就每多一天扣一分,问你怎么写才能让口掉的总分少

这道题就是暴力枚举每一种情况,为了记录所有写作业的情况,而且数据也不是太大(就15),可以用二进制表示写作业的情况,
例如 有3门课 1 1 1(7)表示三门课全写了,他肯定是有(1 0 1,1 1 0 , 0 1 1)就是完成两门课来的,这样就可以想到如何写状态转移方程,具体细节看代码吧 ↓ ↓ ↓

 #include<cstdio>
#include<iostream>
#include<cmath>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
#include<map>
#include<set>
#include<stack>
#include<sstream>
#include<string>
using namespace std;
#define inf 0x3f3f3f3f
struct pp
{string name;  //课名字 int cost;  //写完需要的时间 int dead;  //还有几天交 
}ss[20];    //存课的信息 
struct ps
{int fa,zj,soce,time;//fa 父节点 //zj 记录放的那本书 //soce 扣掉的分数 //做完作业所需的时间 
}dp[1<<15]; 
int main()
{ios::sync_with_stdio(false);   //去cin同步 听说会减时间 int t;cin>>t;while(t--){int n;cin>>n;memset(dp,0,sizeof(dp));  //初始化 for(int i=0;i<n;i++)cin>>ss[i].name>>ss[i].dead>>ss[i].cost;   int end=1<<n;       for(int i=1;i<end;i++)      //枚举任意一种情况 例如 1 1 0 前两门完成 0 0 1 最后一门完成 {   dp[i].soce=inf;                 //初始化 为了找最小所以Inf for(int j=n-1;j>=0;j--)   //看前一步是写的哪一门课的作业 倒着来的原因:If there are more than one orders, you should output the alphabet smallest one. 要输出字典序最小的 {int temp=1<<j;   // temp 代表课的二进制 例第二门课 temp = 1<<(1)(从 0 开始的,所以是 1)就是 1 0 表示写的第二门课 if(temp&i)  //看 i 是由那种状态过来的 {   int tem=i-temp;  //前一种状态 int tt=dp[tem].time+ss[j].cost-ss[j].dead;  //扣掉的分数 ==写完前一门的时间 + 需要写的时间 - 要交的天数 if(tt<0)   //扣掉的分数不可能为负数 归 0 tt=0;if(tt+dp[tem].soce<dp[i].soce)  //比较 就是取每一种状态过来的最大值 {dp[i].soce=tt+dp[tem].soce;  //记录扣掉的分数 dp[i].fa=tem;  //记录父节点 dp[i].zj=j;  //记录写的哪一门课 dp[i].time=dp[tem].time+ss[j].cost;   //记录写完所需时间 }}}}//下面就是输出了 不多说相信大家都能看懂 cout<<dp[end-1].soce<<endl; stack<int>q;  int tt=end-1;;while(dp[tt].time){q.push(dp[tt].zj);tt=dp[tt].fa;}while(!q.empty()){int k=q.top();cout<<ss[k].name<<endl;q.pop();}}return 0;
}

留一个我参考的博客: 传 送 门