HDU 1074 状态压缩DP 作业扣分

来源:互联网 发布:java中bigdecimal相加 编辑:程序博客网 时间:2024/06/11 08:34

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1074

Ignatius刚刚从第30届ACM / ICPC回到学校。 现在他做了很多功课。 每个老师给他一个交付作业的最后期限。 如果Ignatius在截止日期之后交作业,老师将减少他的最后考试成绩,1天1分。 正如你所知,做作业总是需要很长时间。 所以Ignatius希望你帮助他安排做作业的顺序,以减少分数。输出最少扣分的做作业顺序。

输入n,0<n<=15 例子数,课程名,截止日期,完成天数。

23Computer 3 3English 20 1Math 3 23Computer 3 3English 6 3Math 6 3
 

Sample Output
2ComputerMathEnglish3ComputerEnglishMath

思路:这道题有一个明显的标志,N为15,一般N为15 16都是用状态压缩DP。所谓状态压缩DP就是采用二分的思想对应于每一种状态,然后对每种状态从小到大进行更新。n门课,(1<<n)-1,有n个1,表示n门课都完成。若该位为0,表示这门课没有完成。i从1到1<<n  -1,模拟所有情况。对每种情况d[i],假设有m门课完成,肯定是由m-1门状态而来,所以只要遍每门课没完成的的状态,找到最小值。然后+当前课程所扣的分数。

如何找到d[i]中完成的课程,可以用i&(1<<j)表示第j门是否在i中。找到最小值后,把它记录到路径当中。print[i],记录i状态时,最新完成的作业。最终打印的时候可以回溯,先从x=1<<n   -1的情况开始,放到最后输出,然后x-1<<print[x],表示之前的情况,输出。直到x为0.

#include<stdio.h>#include<iostream>using namespace std;const int maxn=(1 << 15) + 10;#define INF  (1 << 31) - 1;int dp[maxn], print[maxn], time[maxn];struct{    char name[110];    int ddl, actual;} a[20];void output(int x){    if (!x)return;     output(x - (1 << print[x]));     printf("%s\n", a[print[x]].name);}int main(){    int T,n,i;    cin >> T;    while (T--)    {        cin >> n;        for (i = 0; i < n; i++)            cin >> a[i].name >> a[i].ddl >> a[i].actual;        int total = 1 << n;        for (i = 1; i < total; i++)//n门做完,1<<n-1都是1        {            dp[i] = INF;            for (int j = n - 1; j >= 0; j--)            {                int temp = 1 << j;//表示第J门是否做                if (!(i&temp))continue;//如果状况iz中第j门不做,跳过                int score = time[i - temp] + a[j].actual - a[j].ddl;                if (score < 0)score = 0;//证明截止时间前就完成了                if (dp[i] > dp[i - temp] + score)//更新状态i的最小值                {                    dp[i] = dp[i - temp] + score;                    time[i] = time[i - temp] + a[j].actual;//记录i情况下的时间                    print[i] = j;                }            }        }        cout << dp[total - 1] << endl;        output(total - 1);    }    return 0;}



原创粉丝点击