第一道状态dp 题~~~~
题目链接:CLICK here
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用二进制表示事件的状态~~~比如有三门功课,用三位二进制来表示这三门功课的状态,000表示三门功课都没完成,001表示只完成了第一门功课,010表示只完成了第二门功课,100表示只完成了第三门功课,依次类推。。。。对于本题来说~n门课程有 2^n个状态分别是从 00...0 到11...1;我们枚举这么多种状态,然后从00...0开始遍历到11...1结束,每当遍历到一种状态的时候,就确定从当前的这种状态到另外一种状态的转移过程;#include <iostream> #include <stdio.h> #include <string.h> #include <string> const int MAX=40000; using namespace std; struct node { int cost; //共花费了多少时间 int reduce;//最少的扣分数 int pre;//它的前一个状态 }dp[MAX]; struct node1 { char name[150]; //科目名称 int deadline; //截止日期 int cost; //需要多少时间完成 }work[20]; bool visited[MAX]; //表示某个状态是否被访问过 void print(int k,int t) //递归输出 { int cnt=0; int v=k^t; //用异或的形式求出对应的课程 while(v) { v>>=1; cnt++; } k=t; t=dp[t].pre; if(t!=-1)print(k,t); printf("%s\n",work[cnt-1].name); } void init() { dp[0].cost=0; dp[0].pre=-1; dp[0].reduce=0; memset(visited,false,sizeof(visited)); visited[0]=true; } int main() { int T,n; cin>>T; while(T--) { init(); cin>>n; for(int i=0;i<n;i++) scanf("%s%d%d",work[i].name,&work[i].deadline,&work[i].cost); int upper=1<<n; int tupper=upper-1; for(int i=0;i<tupper;i++)//遍历状态 for(int j=0;j<n;j++) //遍历n门科目 { int cur=1<<(j); if((cur&i)==0) //判断当前科目有没有完成,注意(cur&i)这个括号不能丢 { int curtemp=cur|i; int day=dp[i].cost+work[j].cost; int reduce=day-work[j].deadline; if(reduce<0)reduce=0; reduce+=dp[i].reduce; if(visited[curtemp]) //如果被访问过,那么取最优 { if(reduce<dp[curtemp].reduce) {dp[curtemp].reduce=reduce; dp[curtemp].pre=i; dp[curtemp].cost=day; } } else if(!visited[curtemp]) //如果没被访问过,则更新 { visited[curtemp]=true; dp[curtemp].reduce=reduce; dp[curtemp].cost=day; dp[curtemp].pre=i; } } } printf("%d\n",dp[tupper].reduce); //输出最终分数 print(tupper,dp[tupper].pre); //递归输出 } return 0; }