hdu 1074 Doing Homework

来源:互联网 发布:昕搜网络 编辑:程序博客网 时间:2024/06/08 05:21

给出n(n15)个作业的需要完成的时间和deadline,求一个作业的排列,使得最后被扣的分最少,对于每个作业,如果在deadline之后完成,超过deadline的时间就是被扣的分数,当然在deadline之前完成就不扣分了


因为是要求一个排列,而且O(2n)的复杂度看起来很科学的样子,所以想到状压dp


dpmask代表已经完成mask中的作业的最小扣的分数,通过枚举哪一个作业最后完成来进行转移


最后要求字典序最小,那么在转移的时候优先考虑字典序最大的前一个状态(因为转移是从后往前的


剩下的就是代码了

#include<stack>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define LL long longconst int maxn = 16;const int INF = 0x3f3f3f3f;int dp[1<<maxn],pre[1<<maxn];int dl[maxn],last[maxn];char arr[maxn][110];int n;int slast(int S){    int ret = 0;    for(int i=0;i<n;i++){        if(S&(1<<i)) ret += last[i];    }    return ret;}int dfs(int S){    if(dp[S] != INF){        return dp[S];    }    int sumer = slast(S);    for(int i=0;i<n;i++){        if(S&(1<<i)){            int ndp = dfs(S-(1<<i)) + max(0,sumer-dl[i]);            if(ndp <= dp[S]){                dp[S] = ndp,pre[S] = i;            }        }    }    return dp[S];}int main(){    int T;    scanf("%d",&T);    while(T-- && ~scanf("%d",&n)){        for(int i=0;i<n;i++){            scanf("%s %d %d",arr[i],&dl[i],&last[i]);        }        int all = (1<<n)-1;        memset(dp,0x3f,sizeof(dp));        memset(pre,-1,sizeof(pre));        dp[0] = 0;        printf("%d\n",dfs(all));        stack<int> S;        while(all){            S.push(pre[all]);            all -= (1<<pre[all]);        }        while(S.empty()==false){            printf("%s\n",arr[S.top()]);            S.pop();        }    }    return 0;}
0 0