HDU1074

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1074

题目大意:T个 test case。对于每个test case,有N门课的作业,对于每门课的作业,对应一个期限D和完成所需时间C。如果没有在期限D之前完成作业,那么每过一天扣一分,问怎么安排做作业的顺序才能使扣分最少。注意,1<=N<=15。

解题思路:

  由于1<=N<=15,可以使用状态压缩DP。用 dp[i] 中的 i 记录已完成的作业,(例,i = 18 = 10010,代表其第2,5门作业已完成,而其他的则未完成,因为左数第2,5位上的数字为1)。

  状态转移方程:以 i 为外循环,在内循环遍历所有作业,对于一个 i ,如果第 j 门作业已经完成,那么不考虑,如果未完成,那么 dp[i|(1<<j)] = min( dp[i|(1<<j)], dp[i] + cal() ). cal()是一个用于计算加上这一门课程后要扣多少分的函数。

  仍然用 vector<int> path[ ] 记录路径。由于在给出课名的时候本身就是按照字典序排列的,而且我们的遍历顺序也是从 0 开始,所以对于里面的什么升序排列不用考虑。

  waring: 移位符号的优先级极低,所以很多时候都要加(),不然会出bug。

 1 #include <cstdio>
 2 #include <vector>
 3 using namespace std;
 4 const int maxn=1<<16;
 5 const int inf=0x7ffffff;
 6 vector<int> path[maxn];
 7 int dp[maxn];
 8 struct classes{
 9     char name[110];
10     int D,C;
11 }cs[20];
12 int cal(int d,int ed){
13     if(ed<=d)   return 0;
14     return ed-d;
15 }
16 int main(){
17     int T,N;
18     scanf("%d",&T);
19     while(T--){
20         scanf("%d",&N);
21         for(int i=0;i<N;i++){
22             scanf("%s",cs[i].name);
23             scanf("%d%d",&cs[i].D,&cs[i].C);
24         }
25         for(int i=0;i<(1<<N);i++){
26             dp[i]=inf;
27             path[i].clear();
28         }
29         dp[0]=0;
30         int days;
31         for(int i=0;i<(1<<N);i++){      //注意括号
32             days=0;
33             for(int j=0;j<N;j++){
34                 if((1<<j)&i)            //括号
35                     days+=cs[j].C;
36             }
37             for(int j=0;j<N;j++){
38                 if((i&(1<<j))==0){      //i&(1<<j)外面一定要加括号
39                     int ca=cal(cs[j].D,days+cs[j].C);
40                     if(dp[i|(1<<j)]>dp[i]+ca){
41                         path[i|(1<<j)]=path[i];
42                         path[i|(1<<j)].push_back(j);
43                         dp[i|(1<<j)]=dp[i]+ca;
44                     }
45                 }
46             }
47         }
48         printf("%d
",dp[(1<<N)-1]);
49         for(int i=0;i<path[(1<<N)-1].size();i++){
50             int ind=path[(1<<N)-1][i];
51             printf("%s
",cs[ind].name);
52         }
53     }
54     return 0;
55 }
View Code
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
原文地址:https://www.cnblogs.com/Blogggggg/p/7276014.html