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种作业,正常情况下有n!种顺序,但是完成作业1 2 3 和 1 3 2,2 1 3,3 2 1,他们完成的作业是一样的,但是因为顺序不同,所以扣除的分数也是不同的,因此考虑把完成相同作业的所有状态压缩成一种,并记录扣的分数最少即可,例如有三门作业,两门写了是0 1 1,1 1 0,1 0 1.子问题就是前一门课程写了所花费的时间,如何分析,结合输出,可以用结构体来进行分析。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn=101;
const int INF=0x3f3f3f3f;
struct Point
{
char str[maxn];
int dead;
int cost;
}point[maxn];
struct father
{
//父亲节点 书本 最后扣的分数 花费时间
int dad,book,score,time;
}dp[1<<15];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>point[i].str>>point[i].dead>>point[i].cost;
}
int end=1<<n;//最多有15种情况
for(int i=1;i<end;i++)//枚举
{
dp[i].score=INF;
for(int j=n-1;j>=0;j--)//倒序输出是因为要按照字典序输出
{
int temp=1<<j;//代表课程的二进制
if(temp&i)//i是哪种状态过来的
{
int tem=i-temp;//前一种状态
int ans=dp[tem].time+point[j].cost-point[j].dead;
//扣掉的分数=写完前一门的时间+写当前门需要花费的时间
//-截止时间
if(ans<0)
{
ans=0;
}
if(ans+dp[tem].score<dp[i].score)
{
dp[i].score=ans+dp[tem].score;
dp[i].dad=tem;//前一种状态
dp[i].book=j;
dp[i].time=dp[tem].time+point[j].cost;
//记录写完所需要的时间
}
}
}
}
cout<<dp[end-1].score<<endl;
stack<int>q;
int tt=end-1;
while(dp[tt].time)
{
q.push(dp[tt].book);
tt=dp[tt].dad;
}
while(!q.empty())
{
int k=q.top();
cout<<point[k].str<<endl;
q.pop();
}
}
return 0;
}
https://blog.youkuaiyun.com/xingyeyongheng/article/details/21742341.
https://blog.youkuaiyun.com/qq_37493070/article/details/77336109.这两篇题解很棒,我是通过这两篇理解的。