HDU - 1074 Doing Homework

input:

2
3
Computer 3 3
English 20 1
Math 3 2
3
Computer 3 3
English 6 3
Math 6 3

output:

2
Computer
Math
English
3
Computer
English
Math

 题目大意:

n个作业,每个有也有截止日期和需要花费的天数。如果超过截止时间一天,分数-1,求如何安排作业的先后,让
扣的分数最少。

 分析:

状态dp。比较巧妙,使用11111的数串表示第1,2,3,5,6的作业都完成了。所以对一个i状态的方案,枚举作
业j,求出完成作业j需要扣掉的分数。详细看代码。

 code:

#define frp

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f;
const ll inf = 0x7fffff;
const int maxn = 1<<15;
const int MAXN = 10000;
int dp[maxn],pre[maxn],T[maxn],deadline[50],cost[50];
string sub[50];
int t;

void print(int x){
    if(!x)return;
    print(x^(1<<pre[x]));
    cout<<sub[pre[x]]<<endl;
}
void solve() {
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=0;i<n;i++){
            cin>>sub[i]>>deadline[i]>>cost[i];
        }
        int sum=1<<n;
        for(int i=1;i<sum;i++){
            dp[i]=inf;
            for(int j=n-1;j>=0;j--){
                int tmp=1<<j;
                //如果i方案里没有完成j作业,则continue;
                if(!(i&tmp))continue;
                tmp=i^tmp;
                //完成j作业所要扣的分数T[]数组是完成tmp的方案的天数
                int minus=T[tmp]+cost[j]-deadline[j];
                if(minus<0)minus=0;
                if(dp[tmp]+minus<dp[i]){
                    dp[i]=dp[tmp]+minus;
                    T[i]=T[tmp]+cost[j];
                    pre[i]=j;
                }
            }
        }
        cout<<dp[sum-1]<<endl;
        print(sum-1);
        memset(pre,0, sizeof(pre));
    }
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef frp
    freopen("D:\\coding\\c_coding\\in.txt", "r", stdin);
//    freopen("D:\\coding\\c_coding\\out.txt", "w", stdout);
#endif
    solve();
    return 0;
}

  

posted @ 2018-09-22 16:51  visualVK  阅读(143)  评论(0编辑  收藏  举报