hdu 1074 状压dp

来源:互联网 发布:网红淘宝店货源 编辑:程序博客网 时间:2024/06/08 13:35

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1074
题意:有n个作业,对于每一个作业有一个deadline,有一个完成这作业所需要的时间。如果超过deadline一天就要扣一分,求怎么安排写作业的顺序才能保证扣的分最少。
思路:
对于每一个作业有三个元素,名字,ddl,所需要的时间。
用不同的状态表示当前作业完成的情况,运用状压dp
定义集合S为已经完成的作业的集合,u为当前集合S中的作业编号。
对于每一个状态也有三个元素,一个为达到这个状态所需要的时间,一个为最少扣的分数,因为还需要记录转移的路径所以需要一个来记录由哪里转移来。

i j 表示不同状态,则i^j表示i 状态剔除j 状态的之外的。
i&j 表示i状态中包含了j的状态。
转移方程:
tmp表示由S-{u}这个状态转移过来,需要多扣的分数。
dp[S].lowscore = min(dp[S].lowscore,dp[S-{u}].lowscore + tmp); (u属于S)
如果更新了扣分,就同时需要记录路径,和更新所需要的时间。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <stack>using namespace std;#define M 20#define INF 0x3f3f3f3fstruct{    int time;    int lowscore;    int pre;}dp[1<<M];struct{    int cost;    int ddl;    char name[109];}course[M];int n;int main(){    //freopen("input.txt","r",stdin);    int t;    scanf("%d",&t);    while(t--)    {        scanf("%d",&n);        for(int i = 0;i < n;i++)        {            scanf("%s %d %d",course[i].name,&course[i].ddl,&course[i].cost);        }        for(int i = 0;i < 1<<n;i++)        {            dp[i].time = 0;            dp[i].lowscore = INF;            dp[i].pre = -1;        }        dp[0].lowscore = 0;        for(int S = 0;S < 1<<n;S++)        {            for(int u = 0;u < n;u++)            {                if(S & (1<<u))                {                    int temp = dp[S^(1<<u)].time + course[u].cost - course[u].ddl;                    if(temp < 0) temp = 0;                    if(dp[S].lowscore >= dp[S^(1<<u)].lowscore + temp) //加上等于号以在相同状态下保证pre 尽可能的大,就能保证前面的尽可能小                    {                        dp[S].pre = u;                        dp[S].lowscore = dp[S^(1<<u)].lowscore + temp;                        dp[S].time = dp[S^(1<<u)].time + course[u].cost;                    }                }            }        }        printf("%d\n",dp[(1<<n)-1].lowscore);        stack<int> ss;        for(int i = (1<<n)-1;;)        {            ss.push(dp[i].pre);            i = i ^ (1<<dp[i].pre);            if(i == 0) break;        }        while(!ss.empty())        {            int temp;            temp = ss.top();            ss.pop();            printf("%s\n",course[temp].name);        }    }    return 0;}
0 0