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.
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
思路:状压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 ",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 ",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 ",bc[i]); 142 }printf("%s ",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 }