首页 > 代码库 > hdu 1074 Doing Homework (状压dp)

hdu 1074 Doing Homework (状压dp)

题目大意:

给出完成n门功课的所需要的时间和n门功课上交时间的deadline。

如果比deadline 晚交一天就要扣一分。

安排出完成顺序使得扣分最少。


思路分析:

dp[s] 表示完成了s 状态下的功课所扣分的最优解。


对于每一个状态,我们转移的时候将每一门没有完成的功课加入其中,这样就保证了逐一完成。


需要注意的是字典序最小的问题,开始的时候对输入的字符串从小到大排序,每次都从小到大加入状态中。


这样就可以保证加入的状态字典序最小。


还要输出方案,所以ans数组里保存了上一个状态和当前状态加入的功课。


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <map>
#include <string>
#define maxn 1005
using namespace std;

int dp[1<<15];
int ans[1<<15][2];
int time[1<<15];
struct node
{
    string str;
    int dead,cost;
    bool operator < (const node &cmp)const
    {
        return str<cmp.str;
    }
}a[20];

void print(int s)
{
    if(s==0)return;
    print(ans[s][0]);
    cout<<a[ans[s][1]].str<<endl;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        for(int i=0;i<n;i++)
            cin>>a[i].str>>a[i].dead>>a[i].cost;
        sort(a,a+n);

        memset(dp,0x3f,sizeof dp);
        memset(time,0,sizeof time);
        memset(ans,0,sizeof ans);

        dp[0]=0;

        for(int s=0;s<(1<<n);s++)
        {
            for(int i=0;i<n;i++)
            {
                if((1<<i)&s)continue;
                int c=max(0,time[s]+a[i].cost-a[i].dead);
                if(dp[s]+c < dp[s|(1<<i)])
                {
                    dp[s|(1<<i)]=dp[s]+c;
                    time[s|(1<<i)]=time[s]+a[i].cost;
                    ans[s|(1<<i)][0]=s;
                    ans[s|(1<<i)][1]=i;
                }
            }
        }

        cout<<dp[(1<<n)-1]<<endl;
        print(ans[(1<<n)-1][0]);
        cout<<a[ans[(1<<n)-1][1]].str<<endl;
    }
    return 0;
}