• HDU1074 Doing Homework(状压dp)


    参考:http://www.cnblogs.com/kuangbin/archive/2011/08/04/2127687.html

    膜拜斌巨orz

    算法核心:状态压缩DP
    大意:
    有n门课程作业,每门作业的截止时间为D,需要花费的时间为C,若作业不能按时完成,每超期1天扣1分。
    这n门作业按课程的字典序先后输入
    问完成这n门作业至少要扣多少分,并输出扣分最少的做作业顺序
    PS:达到扣分最少的方案有多种,请输出字典序最小的那一组方案

    分析:
    n<=15,由题意知,只需对这n份作业进行全排列,选出扣分最少的即可。
    用一个二进制数存储这n份作业的完成情况,第1.。。。n个作业状况分别
    对应二进制数的第0,1.。。。。,n-1位则由题意,故数字上限为2^n
    其中 2^n-1即为n项作业全部完成,0为没有作业完成。。。

    用dp[i]记录完成作业状态为i时的信息(所需时间,前一个状态,最少损失的分数)。
    递推条件如下
    1.状态a能做第i号作业的条件是a中作业i尚未完成,即a&i=0。
    2.若有两个状态dp[a],dp[b]都能到达dp[i],那么选择能使到达i扣分小的那一条路径,若分数相同,转入3
    3.这两种状态扣的分数相同,那么选择字典序小的,由于作业按字典序输入,故即dp[i].pre = min(a,b);

    初始化:dp[0].cost = 0;dp[0].pre=-1;dp[0].reduced = 0;

    最后dp[2^n-1].reduced即为最少扣分,课程安排可递归的输出

    /* ***********************************************
    Author        :devil
    Created Time  :2015/12/9 17:19:27
    ************************************************ */
    
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <queue>
    #include <map>
    #include <set>
    #include <vector>
    #include <cstdio>
    using namespace std;
    const int N=1<<16;
    bool vis[N];
    struct wq
    {
        int pre,cost,lost;//前一状态,所需状态,最少损失的分数
    } dp[N];
    struct we
    {
        int dead,cost;//截止日期,所需日期
        char name[105];
    } c[16];
    void init()
    {
        memset(vis,0,sizeof(vis));
        dp[0].cost=0;
        dp[0].pre=-1;
        dp[0].lost=0;//dp[0]是指所有作业都没有做的状态
        vis[0]=1;
    }
    void output(int now)
    {
        int work=dp[now].pre^now,id=-1;
        while(work)
        {
            id++;
            work>>=1;
        }
        if(dp[now].pre) output(dp[now].pre);
        printf("%s
    ",c[id].name);
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        int t,n;
        scanf("%d",&t);
        while(t--)
        {
            init();
            scanf("%d",&n);
            for(int i=0; i<n; i++)
                scanf("%s%d%d",c[i].name,&c[i].dead,&c[i].cost);
            int upper=(1<<n)-1;//tupper表示成二进制数是n个1的,表示所有的作业都完成了
            for(int i=0; i<upper; i++)//遍历所有状态
            {
                for(int work=0; work<n; work++)//遍历所有作业
                {
                    int cur=1<<work;
                    if(!(cur&i))//该项作业尚未做过
                    {
                        int curtemp=cur|i;
                        int day=dp[i].cost+c[work].cost;
                        dp[curtemp].cost=day;
                        int reduce=day-c[work].dead;
                        if(reduce<0) reduce=0;
                        reduce+=dp[i].lost;
                        if(vis[curtemp])//该状态已有访问信息
                        {
                            if(reduce<dp[curtemp].lost)
                            {
                                dp[curtemp].lost=reduce;
                                dp[curtemp].pre=i;
                            }
                        }
                        else//没有访问过
                        {
                            vis[curtemp]=1;
                            dp[curtemp].lost=reduce;
                            dp[curtemp].pre=i;
                        }
                    }
                }
            }
            printf("%d
    ",dp[upper].lost);
            output(upper);//递归输出
        }
        return 0;
    }
  • 相关阅读:
    关于互联网产品经理的认知
    互联网产品经理的工作职责
    软件需求分析方法
    Enumeration遍历http请求参数的一个例子
    jquery datatable使用简单示例
    改变输出的文字的字体格式
    excel 类获取起始列和使用列
    调试不能命中断点
    CString转换为const char*
    __declspec(dllexport)
  • 原文地址:https://www.cnblogs.com/d-e-v-i-l/p/5033511.html
Copyright © 2020-2023  润新知