HDU--1074(状态压缩DP)

典型的状态压缩DP,给出了每件作业的截止时间和花费,求让老师扣分最少的写作业方式。把完成n种作业用状态2^n-1表示,dp[s]表示

完成状态s时,最小扣分。比如“111”,那么可以由“011”,“110”,“101”转移过来,分别表示选了0,1号作业,1,2号作业,0,2号作业。

t【s】表示状态S记录的总时间。dp[s] = min{dp[j]+c[k] - d[k]},其中j = i^(1<<k),0<k<n;pre【s】表示状态s完成时,最末尾完成的作业,

#include<cstdio>
#include<iostream>
#include<climits>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#define INF INT_MAX
using namespace std;
typedef long long ll;
const int maxn = 100;

char w[20][150];
int d[20],c[20];
int dp[1<<15];
int t[1<<15];
int pre[1<<15];

void print(int st)
{
    if(st == 0) return ;
    int x = pre[st];
    st = st-(1<<x);
    print(st);
    printf("%s\n",w[x]);
}
int main()
{
    freopen("in","r",stdin);
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        getchar();
        for(int i = 0; i < n; ++i)
        {
            scanf("%s%d%d",w[i],d+i,c+i);
            getchar();
        }

        //printf("^^^\n");
        for(int i = 1; i <= (1<<n)-1; ++i)
        {
            dp[i] = INF;
            for(int k = 0; k < n; ++k)
            {
                if((i&(1<<k)) != 0)
                {
                    int j = i-(1<<k);
                    int score = t[j] + c[k]-d[k];
                    if(score < 0) score = 0;
                    if(dp[j] + score <= dp[i])//由于dp的方向是从0-2^n-1递推的,所以当出现dp值相同的状态时应该选K大的放在末尾。这样,K小的还可以在前面的决策中再选。。
                    {
                        dp[i] = dp[j] + score;
                        t[i] = t[j]+c[k];
                        pre[i] = k;
                        printf("%d %d\n",i,pre[i]);
                    }
                }
            }
        }

        printf("%d  \n",dp[(1<<n)-1]);
        print((1<<n)-1);
        memset(t,0,sizeof(t));
        memset(pre,0,sizeof(pre));
        memset(dp,0,sizeof(dp));

    }

}

 

posted @ 2015-09-07 22:17  Norlan  阅读(197)  评论(0编辑  收藏  举报