1. 程式人生 > >hdu 1074 Doing Homework(狀壓DP)

hdu 1074 Doing Homework(狀壓DP)

Doing Homework

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>

using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = (1<<15)+10;

struct node {
    int deadline;//截止時間
    int how_day;//花費的時間
    char name[110];
} nxt[20];

int dp[maxn];
int time[maxn];
int print[maxn];

void output(int x) { //列印路徑 dfs
    if(!x)
        return;

    output( x - (1<<print[x]) );

    printf("%s\n", nxt[print[x]].name);//字典序
}

int main() {
    freopen("data.in", "r", stdin);
    int T, n;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
            scanf("%s %d %d", nxt[i].name, &nxt[i].deadline, &nxt[i].how_day);
        int total = 1<<n;

        memset(time, 0, sizeof(time));
        memset(print, 0, sizeof(print));
        memset(dp, 0, sizeof(dp));

        //全排列問題,狀壓dp
        for(int i = 1; i < total; i++) {
            dp[i] = INF;

            for(int j = n-1; j >= 0; j--) {
                int temp = 1<<j;
                if(!(i & temp))
                    continue;//沒有寫j門課的作業則跳出迴圈

                int score = time[i-temp] + nxt[j].how_day - nxt[j].deadline;//扣得分數
                score = max(score,0);//扣得分數不可能是負的
                if(dp[i] > dp[i-temp] + score) { //如果當前狀態可以更優則更新dp值,和time的值
                    dp[i] = dp[i-temp] + score;
                    time[i] = time[i-temp] + nxt[j].how_day;
                    print[i] = j;//修改路徑
                }
            }
        }
        //所有課作業做完應該所有為都為1,就是1<<n-1
        printf("%d\n", dp[total-1]);//輸出扣得分數
        output(total - 1);//列印路徑
    }

    return 0;
}