// [9/11/2014 Sjm] /* hdu 1074 (状态压缩) dp[i]: 表示在 i 状态时的最优解 (i状态: i数值用二进制表示, 若二进制数第 n 位为1,代表第 n 个课程已被计算) 思路: 详见代码注释(举几个简单例子模拟一下,可以明白的更清楚一些) */#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <string> using namespace std; const int MAX = 1 << 16, MAX_N = 20, INF = 0x3f3f3f3f; int N; bool Vis[MAX]; struct myNode { int nowTime; // 当前时间 int pre; // 前一个状态 int minReduce; // 被扣掉的分数 } dp[MAX]; struct mySubject { string name; // 课程名 int deadline; // 最后期限 int cost; // 所需要花费的时间 } subject[MAX_N]; int getPos(int x) { int pos = 0; while (x) { ++pos; x >>= 1; } return (pos - 1); } void Output(int State) { if (0 == State) return; int nowSub = (State^dp[State].pre); // 为了获取当前课程是第几个 ==> getPos(nowSub) Output(dp[State].pre); cout << subject[getPos(nowSub)].name << endl; } void Solve() { memset(Vis, false, sizeof(Vis)); for (int i = 0; i < N; ++i) dp[i].minReduce = INF; dp[0].nowTime = 0; dp[0].pre = -1; dp[0].minReduce = 0; Vis[0] = true; int finalState = (1<<N) - 1; for (int state = 0; state < finalState; ++state) { // 遍历所有状态 for (int subPos = 0; subPos < N; ++subPos) { // 在当前状态下加入subPos课程 int sub = (1 << subPos); if (0 == (sub&state)) { // 判断当前subPos课程是否已经计算过,若没有则进行计算,否则需寻找其他课程 int nowState = state | sub; // 计算过subPos课程后,所到达的新的状态 int finish_nowState_Time = dp[state].nowTime + subject[subPos].cost; // 完成subPos课程后,整个状态所到达的时间 int nowStateReduce = finish_nowState_Time - subject[subPos].deadline; if (nowStateReduce < 0) nowStateReduce = 0; // 仅仅因为subPos课程所需要被扣掉的分数 nowStateReduce = dp[state].minReduce + nowStateReduce; // 完成subPos课程后,整个状态需要被扣掉的分数 if (Vis[nowState]) { // 若新的状态之前到达过,则与完成subPos课程到达此状态时,所被扣掉的分数进行比较 // 若之前到达该状态时,所被扣掉的分数 > 完成subPos课程到达此状态时,所被扣掉的分数 // 则对该状态进行更新 if (dp[nowState].minReduce > nowStateReduce) { dp[nowState].minReduce = nowStateReduce; dp[nowState].pre = state; dp[nowState].nowTime = finish_nowState_Time; } } else { // 若新的状态之前没有到达过,直接赋值更新 Vis[nowState] = true; dp[nowState].minReduce = nowStateReduce; dp[nowState].pre = state; dp[nowState].nowTime = finish_nowState_Time; } } } } printf("%d\n", dp[finalState].minReduce); Output(finalState); // 递归输出所选择课程的顺序 } int main() { //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); int Case; scanf("%d", &Case); while (Case--) { scanf("%d", &N); for (int i = 0; i < N; ++i) { cin >> subject[i].name; scanf("%d %d", &subject[i].deadline, &subject[i].cost); } Solve(); } return 0; }
状态压缩 之 hdu 1074 Doing Homework
最新推荐文章于 2019-08-14 06:48:04 发布