您的位置:首页 > 其它

HDU - 1074 Doing Homework(状压DP)

2017-08-14 09:28 501 查看
Problem Description

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

题目大意: 一共有N种作业要去作, 每个作业都有一个最后期限,和要完成需要花费的时间。每项作业晚交一天,就会有一天的罚时, 问你怎么安排作业才能让罚时最少, 并输出完成作业是先后顺序。

大体思路: 因为作业数量不多, 用int的15位表示表示一项作业是否完成(1代表完成,0代表没完成, 可能和一些人表示法不一样), 枚举出所有方案并动态规划。

#include <bits/stdc++.h>

using namespace std;
struct info//用来记录输入的结构体
{
char name[150];//作业的名字
int dea;//最后期限
int tim;//完成所需的时间
}a[20];
struct node//用于dp的结构体
{
int penalty;//记载罚时
int time;//记载此状态下当前时间
int pre;//上一项完成的作业,指向a的下标
int now;//记载当前完成的作业
}dp[(1 << 15) + 1];
void _back(int n)//用于回溯输出完成方案
{
if(dp
.pre == -1)
{
return;
}
_back(dp
.pre);
printf("%s\n", a[dp
.now].name);
}
int main()
{
int t, n;
while(scanf("%d",&t)!= EOF)
{
while(t-- && scanf("%d", &n))
{
for(int i = 0; i < n; i++)
{
scanf("%s %d %d", a[i].name, &a[i].dea, &a[i].tim);
getchar();
}
int enu = (1 << n);//所有可行的enu - 1种方案
for(int i = 0; i <= enu; i++)//结构体初始化, 罚时设为无穷
{
dp[i].penalty = 0x3f3f3f3f;
dp[i].time = 0;
}
dp[0].penalty = 0;
dp[0].pre = -1;//标记最开始的状态
for(int i = 1; i < enu; i++)//枚举各种方案
{
for(int j = n - 1; j >= 0; j--)//把int 15位跑一遍
{
int tmp = (1 << j);//将1送到j位
if(tmp & i)//判断这位是否为1
{
int past = i - tmp;//上一个此作业未完成的状态
int x = dp[past].time + a[j].tim - a[j].dea;//从上一状态到这一状态的罚时
x = max(0, x);
if(x + dp[past].penalty < dp[i].penalty)//从上一状态到这一状态罚时小于当前已有的罚时时更新
{
dp[i].penalty = x + dp[past].penalty;
dp[i].time = dp[past].time + a[j].tim;
dp[i].pre = past;//记载路径,方便back函数回溯
dp[i].now = j;
}
}
}
}
printf("%d\n", dp[enu - 1].penalty);
_back(enu - 1);//回溯输出路径
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp 状压dp