状态DP Doing Homework HDU - 1074

题目大意: 给出n种作业,每个作业的名字,截止时间和所需的时间,超过截止时间的作业,每超过一天要扣一分,要你合理的安排作业的顺序使得扣掉的分数最少。

思路:一直觉得可以用贪心,然而不对。1代表完成作业,0代表还未完成的作业,枚举所有的状态,推出并更新下一个状态。例如3个作业的话0(000)可以推出 001,010,100这三种状态,而011可以由 001或者010推出,选这两者中的最小值。

http://www.cppblog.com/notonlysuccess/archive/2009/02/18/74168.aspx

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#define inf 0x3f3f3f3f
#define maxn 16
using namespace std;
typedef struct
{
    string s;
    int de,c;
}P;
P a[maxn];
int dp[1<<maxn],pre[1<<maxn],n;
void print(int x)
{
    if(x==0) return ;
    print(pre[x]);
    int t;
    for(int i=0;i<n;i++)
        if((x&(1<<i))!=0&&(pre[x]&(1<<i))==0)
            t=i;
    cout<<a[t].s<<endl;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            cin>>a[i].s>>a[i].de>>a[i].c;
        for(int i=1;i<(1<<n);i++)
            dp[i]=inf;
        dp[0]=0;
        for(int i=0;i<(1<<n);i++)
        {
            int s=0;
            for(int k=0;k<n;k++)
                if(i&(1<<k)) s+=a[k].c;
            for(int j=0;j<n;j++)
            {
                if((i&(1<<j))==0)
                {
                    int ss=s;
                    ss+=a[j].c;
                    if(ss>a[j].de) ss=ss-a[j].de;
                    else ss=0;
                    if(dp[i|(1<<j)]>dp[i]+ss)
                    {
                        dp[i|(1<<j)]=dp[i]+ss;
                        pre[i|(1<<j)]=i;
                    }
                }
            }
        }
        printf("%d\n",dp[(1<<n)-1]);
        print((1<<n)-1);
    }
    return 0;
}

 

posted @ 2017-08-16 16:28  Twsc  阅读(193)  评论(0编辑  收藏  举报