HDU 1074 Doing Homework 状态压缩DP

题目大意:

现在又n中不同的作业需要做,每种作业有一个上交期限可完成需要的时间,对于任何一门作业,超出那门作业的提交日期每一天那门课将会扣一分,求使得扣分最少的条件下应该如何安排写作业的顺序,输出写作业的顺序,如果有多组解那么输出字典序最小的方案


大致思路:

刚开始以为是个贪心的策略,后来发现不对,,,

这是个状态压缩DP对于每一门课的作业有两种状态,完成货没有完成,那么用dp[ i ] 表示当前作业状态( i 的二进制对应位置上式1或者0表示那门课是否完成) 这样

dp[ i ] = min( dp[ i 少一个 1 ] + 那门课的罚时)

很基础的一个状态压缩dp

代码如下:

Result  :  Accepted     Memory  :  716 KB     Time  :  15 ms

/*
 * Author: Gatevin
 * Created Time:  2014/8/13 20:50:48
 * File Name: haha.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

const int inf = 0x7fffffff;

struct subj
{
    int C,D;
    string name;
    subj(int c, int d, string s) : C(c) , D(d), name(s){}
    subj(){}
};

subj sub[20];
int dp[1 << 16];
int pre[1 << 16];
int cost[1 << 16];
vector <int> answer;

int main()
{
    int t,n;
    int c,d;
    string s;
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i = 0; i < n; i++)
        {
            cin>>s>>d>>c;
            sub[i] = subj(c,d,s);
        }
        for(int i = 1; i <= (1 << n) - 1; i++)
        {
            dp[i] = inf;
        }
        dp[0] = 0;
        cost[0] = 0;
        for(int i = 0; i <= (1 << n) - 1; i++)
        {
            for(int j = 0; j < n; j++)
            {
                int tmp = 1 << j;
                if(i & tmp)
                {
                    cost[i] = cost[i & (~tmp)] + sub[j].C;
                    if(cost[i] > sub[j].D)
                    {
                        if(dp[i] >= dp[i & (~tmp)] + cost[i] - sub[j].D)
                        {
                            dp[i] = dp[i &(~tmp)] + cost[i] - sub[j].D;
                            if(dp[i] == dp[i & (~tmp)] + cost[i] - sub[j].D)
                            {
                                if(sub[j].name < sub[pre[i]].name)
                                {
                                    pre[i] = j;
                                    continue;
                                }
                            }
                            pre[i] = j;
                        }
                    }
                    else
                    {
                        if(dp[i] >= dp[i & (~tmp)])
                        {
                            dp[i] = dp[i & (~tmp)];
                            if(dp[i] == dp[i & (~tmp)])
                            {
                                if(sub[j].name < sub[pre[i]].name)
                                {
                                    pre[i] = j;
                                    continue;
                                }
                            }
                            pre[i] = j;
                        }
                    }
                }
            }
        }
        cout<<dp[(1 << n) - 1]<<endl;
        int now = (1 << n) - 1;
        while(now != 0)
        {
            answer.push_back(pre[now]);
            now = now & (~(1 << pre[now]));
        }
        for(unsigned int k = answer.size() - 1; k < answer.size(); k--)
        {
            cout<<sub[answer[k]].name<<endl;
        }
        answer.clear();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值