HDU 1074 Doing Homework (状压DP + 路径记录)

来源:互联网 发布:网络经常被攻击 编辑:程序博客网 时间:2024/06/05 22:35

前面虽然自己已经了几篇状压DP的题解,但是这道题才是我的第一道状压DP题。


题意:有n个任务,每个任务有两个属性(d :最后期限 c :需要用的天数),主人公必须一项一项完成任务,并且每个任务完成的时间每超出最后期限一天,就要被扣一分。问他能被扣的最少的分数。多情况字典序输出方案。


设dp[S] 为完成状态S中的所有任务的被扣最少分数。

那么dp[S] = min(dp[S],dp[S-{v}] + cost);

cost 为 完成S中的所有任务所用的总时间 - 完成v的最后期限。

因为输出按照字典序,所以枚举v的时候逆序。这个稍微一想应该就明白。


我的代码:

#include<cstdio>#include<iostream>#include<stack>using namespace std;const int inf = 0x3f3f3f3f;const int maxn = 16;struct Nod{    char name[105];    int d,c;}node[maxn];int dp[1<<maxn],pre[1<<maxn];int n;void solve(){    int Ed = 1 << n;    fill(dp,dp+Ed,inf);    fill(pre,pre+Ed,-1);    int day,cost,S0,tmp,cnt;    dp[0] = 0;    for(int S = 1;S < Ed; S++){        for(int v = n - 1; v >= 0 ; v--){            if(!(S >> v & 1)) continue;            S0 = S - (1 << v);            day = 0;cost = 0;            for(int i = 0; i < n ; i++){                if(S0 >> i & 1) day += node[i].c;            }            if(node[v].d < day + node[v].c) cost = day + node[v].c - node[v].d;            if(dp[S] > dp[S0] + cost){                dp[S] = dp[S0] + cost;                pre[S] = S0;                //cout<<S<<" "<<S0<<" "<<v<<" "<<dp[S]<<endl;            }        }    }    printf("%d\n",dp[Ed-1]);    tmp = Ed - 1;    stack<int> stk;    while(pre[tmp] != -1){        cnt = 0;        while(!((tmp ^ pre[tmp]) >> cnt & 1)) cnt++;        stk.push(cnt);        tmp = pre[tmp];    }    while(!stk.empty()){        int top = stk.top();stk.pop();        printf("%s\n",node[top].name);    }}int main(){    int cas;    scanf("%d",&cas);    while(cas--){        scanf("%d",&n);        for(int i = 0 ;i < n; i++){            scanf("%s%d%d",node[i].name,&node[i].d,&node[i].c);        }        solve();    }    return 0;}


0 0