您的位置:首页 > 其它

hdu 1074 Doing Homework

2016-05-06 12:42 357 查看
二进制状态压缩dp,第一次接触这个算法,同时吐槽一下自己:自己之前写博客从来不加注释,觉得自己会就OK了,博客是给自己看的,从没注意过看我博客的人的想法。 然而既然别人看你博客,那肯定是要学习你会然而别人不会的知识,如果不加注释的话,别人肯定看不懂,浪费别人的时间。自己写这道题深有体会, 看了好多大牛的博客,然而他们好多没加注释,搞得我根本就不知道他们写的是什么,自己想这道题想了好久,最后找到了一位写有注释的大牛的博客,终于看懂了。

这题起初我自己写想的是搜索,写完之后果断TLE,自己一算复杂度,15的阶乘1W亿,,Orz。

用二进制状态压缩,比如要求15门作业的最优解,那么肯定是从14门作业再添加一门,若完成14门作业的最优解已知的话,那么15门肯定是完成14门作业加上剩下的一门作业,因为剩下的一门有15种情况,(即第一门,第二门,…..第15门未完成),然后在这15种情况下再找到最优的一个,所以可以从前到后这样一步一步的求,分别求出第一门,第二门,,,,第n门的最优解,

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=1074

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

Hint

In the second test case, both Computer->English->Math and Computer->Math->English leads to reduce 3 points, but the

word “English” appears earlier than the word “Math”, so we choose the first order. That is so-called alphabet order.

代码:

#include<stdio.h>
#include<string.h>
using namespace std;
const int maxn=(1<<15)+10;//千万不能写成(1<<15+10),+的运算符优先于<<。
const int inf=(1<<31)-1;//+oo
struct
{
int limit,actual;  //limit限制时间,actual实际所用时间
char name[110];
} a[20];
int dp[maxn],print[maxn],time[maxn]; //dp[]表示在这个状态对应被扣多少分,time[]表示在这个状态用了多少时间。这里所指的状态是指dp[i]中的i转化为二进制时对应的01串对应的状态,比如6为110,代表做了第二门和第三门作业,而第一门作业没做时的状态。
void output(int x)  //倒过来打印路径
{
if(!x) return;
output(x-(1<<print[x]));
printf("%s\n",a[print[x]].name);
}
int main()
{
int nn,n;
scanf("%d",&nn);
while(nn--)
{
memset(time,0,sizeof(time));
int n,i,j;
scanf("%d",&n);
for(i=0; i<n; i++)
scanf("%s%d%d",a[i].name,&a[i].limit,&a[i].actual);
int total=1<<n;
for(i=1; i<total; i++)  //不要用十进制来看待i,应该用二进制来看待,二进制的第j位中0代表没有写第n门作业,1代表写了第j门作业
{
dp[i]=inf;   //初始化状态为无穷大
for(j=n-1; j>=0; j--)  //分别查找第j门(j+1门),因为要顺着输出所以要从后往前判断,比如有两门作业完成后分数相同,在这种情况下,起初位于前面的作业位于前面
{
int temp=1<<j;   //判断第j门(j+1门);
if(!(i&temp))  continue; //若第j门没有做,跳出循环。
int score=time[i-temp]+a[j].actual-a[j].limit;//最后做第j门作业,对应的被扣分数的为多少,
if(score<0) score^=score;   //不可能存在被扣分数为负,若负则为0;
if(dp[i]>dp[i-temp]+score)    //若最后做第j门作业,所扣的分数少于之前的分数:
{
dp[i]=dp[i-temp]+score;  //就将此状态作为此状态最优解,
time[i]=time[i-temp]+a[j].actual;//此状态对应所用时间更新。
print[i]=j;  //用来记录路径,最后要打印。
}
}
}
printf("%d\n",dp[total-1]);  //n门功课全部做完对应的状态是n个1,即(1<<n)-1,即total-1;
output(total-1); //打印路径要倒过来打印,比如print[total-1]时对应的是最后一门作业做的是哪一门,然后total-1-(1<<print[total-1])对应的是除去倒数第一门作业时,对应的状态
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: