Doing Homework(hdu)1074

Doing Homework

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6967    Accepted Submission(s): 3043

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.

Author

Ignatius.L

Recommend

We have carefully selected several similar problems for you:  1025 1080 1158 1069 1059

思路:状压DP.

一开始想全排列,往这思路上想,这样谁都知道会超时,因为n<15;那么共有pow(2,n)的状态,那么状压dp可解决.

每个状态可由前面多个状态转移而来,所以取最小就是这个状态的最优解,局部最优,最后到整体最优。

状态转移方程和解释具体看下面代码

  1 #include<stdio.h>
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<string.h>
  5 #include<stdlib.h>
  6 #include<queue>
  7 #include<stack>
  8 #define sc(x) scanf("%I64d",&x)
  9 #define pr(x) printf("%I64d",x);
 10 #define prr(x) printf("%I64d\n",x);
 11 #define prrr(x) printf(" %I64d",x);
 12 #define FOR(i,p,q) for(int i=p;i<=q;i++)
 13 int cmp(char *p,char *q);
 14 typedef struct pp
 15 {
 16     int x;
 17     int y;
 18     char a[200];
 19 } ss;
 20 ss ab[20];
 21 char bc[20][200];
 22 const int N=1e9;
 23 typedef struct qq
 24 {
 25     int time;
 26     int pre;
 27     int no;
 28     int cost;
 29 } kk;//结构体存这个状态的时间当前加入作业的编号,所罚的时间,和前一个状态
 30 kk dp[1<<15+1];
 31 using namespace std;
 32 int main(void)
 33 {
 34     int n,i,j,k,p,q;
 35     scanf("%d",&k);
 36     while(k--)
 37     {
 38         scanf("%d",&n);
 39         for(i=0; i<n; i++)
 40         {
 41             scanf("%s",ab[i].a);
 42             scanf("%d %d",&ab[i].x,&ab[i].y);
 43         }
 44         for(i=0; i<(1<<15)+1; i++)
 45         {
 46             dp[i].cost=N;
 47         }//初始化
 48         dp[0].cost=0;
 49         dp[0].pre=-1;
 50         dp[0].time=0;//开始的时间等状态
 51         for(i=1; i<(1<<n); i++)
 52         {
 53             for(j=0; j<n; j++)
 54             {
 55                 if(i&(1<<j))//当前这个状态含有第j个作业
 56                 {
 57                     if(ab[j].x<=dp[i^(1<<j)].time)//找不含j的前一个状态,并用前一个状态结束时间与第j个作业截至时间比较,然后分情况讨论下
 58                     {
 59                         int cc=dp[i^(1<<j)].time-ab[j].x;
 60                         if(dp[i].cost>dp[i^(1<<j)].cost+cc+ab[j].y)
 61                         {
 62                             dp[i].cost=dp[i^(1<<j)].cost+cc+ab[j].y;
 63                             dp[i].pre=i^(1<<j);
 64                             dp[i].no=j;
 65                             dp[i].time=dp[i^(1<<j)].time+ab[j].y;
 66                         }
 67                         else if(dp[i].cost==dp[i^(1<<j)].cost+cc+ab[j].y)
 68                         {
 69                             if(cmp(ab[j].a,ab[dp[i].no].a)>0)//按字典序排序,将最大的放最后,因为没个都是两两比较
 70                             {
 71                                 dp[i].cost=dp[i^(1<<j)].cost+cc+ab[j].y;
 72                                 dp[i].pre=i^(1<<j);
 73                                 dp[i].no=j;
 74                                 dp[i].time=dp[i^(1<<j)].time+ab[j].y;
 75                             }
 76                         }
 77                     }
 78                     else
 79                     {
 80                         int uu=ab[j].y+dp[i^(1<<j)].time;
 81                         int cc=uu-ab[j].x;
 82                         if(cc<=0)
 83                         {
 84                             if(dp[i].cost>dp[i^(1<<j)].cost)
 85                             {
 86                                 dp[i].cost=dp[i^(1<<j)].cost;
 87                                 dp[i].pre=i^(1<<j);
 88                                 dp[i].no=j;
 89                                 dp[i].time=dp[i^(1<<j)].time+ab[j].y;
 90                             }
 91                             else if(dp[i].cost==dp[i^(1<<j)].cost)
 92                             {
 93                                 if(cmp(ab[j].a,ab[dp[i].no].a)>0)
 94                                 {
 95                                     dp[i].cost=dp[i^(1<<j)].cost;
 96                                     dp[i].pre=i^(1<<j);
 97                                     dp[i].no=j;
 98                                     dp[i].time=dp[i^(1<<j)].time+ab[j].y;
 99                                 }
100                             }
101
102                         }
103                         else
104                         {
105                             if(dp[i].cost>dp[i^(1<<j)].cost+cc)
106                             {
107                                 dp[i].cost=dp[i^(1<<j)].cost+cc;
108                                 dp[i].pre=i^(1<<j);
109                                 dp[i].no=j;
110                                 dp[i].time=dp[i^(1<<j)].time+ab[j].y;
111                             }
112                             else if(dp[i].cost==dp[i^(1<<j)].cost+cc)
113                             {
114                                 if(cmp(ab[j].a,ab[dp[i].no].a)>0)
115                                 {
116                                     dp[i].cost=dp[i^(1<<j)].cost+cc;
117                                     dp[i].pre=i^(1<<j);
118                                     dp[i].no=j;
119                                     dp[i].time=dp[i^(1<<j)].time+ab[j].y;
120                                 }
121                             }
122
123                         }
124
125                     }
126                 }
127             }
128         }
129       printf("%d\n",dp[(1<<n)-1].cost);
130         int pf=dp[(1<<n)-1].pre;
131         int zk=0;
132         while(zk<n-1)
133         {
134
135             strcpy(bc[zk],ab[dp[pf].no].a);
136             zk++;
137           pf=dp[pf].pre;
138         }
139         for(i=n-2;i>=0;i--)
140         {
141             printf("%s\n",bc[i]);
142         }printf("%s\n",ab[dp[(1<<n)-1].no].a);
143     }
144
145
146 }
147 int cmp(char *p,char *q)
148 {
149     return strcmp(p,q);
150 }

状压DP

时间: 2024-10-12 20:09:47

Doing Homework(hdu)1074的相关文章

(HDU)1037 --Keep on Truckin&#39;(待在卡丁车上)

题目链接:http://vjudge.net/problem/HDU-1037 告诉你三个通道的高度和车的高度,按顺序判断能否通过. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 int main() 7 { 8 int a,b,c; 9 scanf("%d %d %d",&a,&b,&c);

(HDU)1098 -- Ignatius&#39;s puzzle(Ignatius的困惑)

题目链接:http://vjudge.net/problem/HDU-1098 求解思路: f(x)=5*x^13+13*x^5+k*a*x; 其中题中"f(x)|65"表示对于任意的整数x,f(x)都能被65整除.所以不难推断:f(x+1)|65也成立. f(x+1)=5*(x+1)^13+13*(x+1)^5+k*a*(x+1), 根据二项式定理:(a+b)^n=C(n,0)a^n+C(n,1)a^(n-1)*b+C(n,2)a^(n-2)*b^2+...+C(n,n)b^n 得:

(hdu)5391 Zball in Tina Town

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5391 Problem Description Tina Town is a friendly place. People there care about each other. Tina has a ball called zball. Zball is magic. It grows larger every day. On the first day, it becomes 1 t

(HDU)1046 -- 完数

题目链接:https://vjudge.net/problem/HDU-1406 注意是所有的因子之和,重复出现的因子不要累加(如果模拟了除法的话),另外给出的两个整数要比较大小(坑). 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <iostream> 5 #include <algorithm> 6 #include <string>

(HDU)1014 --Uniform Generator(统一随机数生成)

这个题目不难,关键是看懂英文:(判断两个数是否互质,而且注意输出的格式) 描述 计算机模拟通常需要随机数.生成伪随机数的一种方式是通过一定形式的函数: seed(x + 1)= [seed(x)+ STEP]%MOD 其中'%'是模运算符. 这样的函数将生成在0和MOD-1之间的伪随机数(种子).这种形式的作用的一个问题就是,它们将总是重复地生成相同的模式. 为了最小化这种影响,仔细选择STEP和MOD值,可以使得在0和MOD-1(包括这两者)之间的所有值的均匀分布. 例如,如果STEP = 3

(HDU)1005 -- Number Sequence(数列)

问题描述 数列定义如下: f(1)= 1,f(2)= 1,f(n)=(A * f(n-1)+ B * f(n-2))mod 7. 给定A,B和n,你要计算f(n)的值. 输入 输入由多个测试用例组成. 每个测试用例在一行(1 <= A,B <= 1000,1 <= n <= 100,000,000)中包含3个整数A,B和n.三个零表示输入结束,此测试用例不进行处理. 输出 对于每个测试用例,在一行上输出f(n)的值. 样例输入 1 1 3 1 2 10 0 0 0 样例输出 2 5

(HDU)1017 --A Mathematical Curiosity(数学好奇心)

描述 给定两个整数n和m,计数整数对(a,b)的数目,使得0 <a <b <n,并且(a ^ 2 + b ^ 2 + m)/(ab)是一个整数. 这个问题包含多个测试用例! 输入的第一行是整数N,然后是空白行,后跟N个输入块. 每个输入块采用问题说明中指示的格式. 输入块之间有空行. 输出格式由N个输出块组成. 输出块之间有一个空行. 输入 您将在输入中获得多个样例. 每个情况由包含整数n和m的行指定. 输入结束由n = m = 0的情况表示.您可以假设0 <n <= 100

(HDU)1040 --As Easy As A+B(像A+B一样简单)

题目链接:http://vjudge.net/problem/HDU-1040 思路:排序算法的水题.注意输出格式,数字之间有空格. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 int main() 7 { 8 int n,num,i,j,temp; 9 int s[1010]; 10 scanf("%d",&

(HDU)1061 --Rightmost Digit( 最右边的数字)

题目链接:http://vjudge.net/problem/HDU-1061 这个题目要求出N个N相乘的个位,直接求结果肯定数据溢出. 其实只要每次得出一个数字保留个位和N相乘就可以了, 因为A*B=C,对于个位而言,A(个位)*B(个位)=C(个位)始终成立. 1<=N<=1,000,000,000,这样写还是TLE了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 us