HDU 1074 Doing Homework
题意: 输入t表示样例数目,输入n表示有n个科目,输入n行,每行有 name,endtime,costtime。超过endtime的一个扣一分,求需要扣最少的分数。
分析:压缩状态,每次状态都可能由很多种状态转化过来,找出扣分最少的,更新当前状态的值。
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <queue> using namespace std; struct subject { char Name[111]; int End, Cost; } S[1<<16]; struct DP { int cost; int reduced; int pre; } dp[1<<16]; int visit[1<<16]; void print(int date) { if(date == 0) { return ; } int which; which = date^dp[date].pre; int number=0; while(which) { which>>=1; number++; } print(dp[date].pre); printf("%s\n", S[number-1].Name); } int main() { int t, n; scanf("%d", &t); while(t--) { scanf("%d", &n); for(int i=0; i<n; i++) { scanf(" %s %d %d", S[i].Name, &S[i].End, &S[i].Cost); } int e = (1<<n)-1; dp[0].cost=0; dp[0].pre=-1; dp[0].reduced = 0; visit[0] = 1; memset(visit, 0, sizeof(visit)); for(int i=0; i<e; i++) { for(int j=0; j<n; j++) { int date1 = 1<<j; if( (i&date1)==0)//这个作业没做过 { int date2 = i|date1; dp[date2].cost = dp[i].cost + S[j].Cost; int reduce = dp[date2].cost - S[j].End; if(reduce<0) reduce = 0; reduce += dp[i].reduced; if(visit[date2])//之前状态存在过 { if(reduce<dp[date2].reduced) { dp[date2].reduced = reduce; dp[date2].pre = i; } } else { visit[date2] = 1; dp[date2].reduced = reduce; dp[date2].pre = i; } } } } printf("%d\n", dp[e].reduced); print(e); } return 0; }