zoukankan      html  css  js  c++  java
  • doing home work(dp-二进制法枚举

    题目 : 给一些不同科目作业(至多15)的完成所需时间和截止时间,每当超过完成时间1天,就会扣一分,求扣分最少的完成顺序及所扣分数;

    Sample Input
    
        2
        3
        Computer 3 3
        English 20 1
        Math 3 2
        3
        Computer 3 3
        English 6 3
        Math 6 3
    
    Sample Output
    
        2
        Computer
        Math
        English
        3
        Computer
        English
        Math

    并不知道什么是状压dp(挠头,刚开始按dead-cost算了一下,果然不对

    看过解答,仍不知什么是状压dp,发现这道题的dp状态描述是按二进制法子集枚举描述的

    因为每时刻的一种静止状态都可以用每种科目 做或没做 这两种状态描述,而情况至多有2^15种,dp所占空间并不会太大

    所以状态用二进制法描述,状态的转移方向是上一步的状态,以二进制的扫描实现

    转移方程 dp【选择此步做了某种作业的某种状态 i】=min( dp【做该种作业之前的状态 i-1】+【i】扣的分数,dp【i】);

    因为是向前转移,所以填充方向从始态开始

    #include<bits/stdc++.h>
    using namespace std;
    const int INF=0x3f3f3f3f;
    
    struct sub{
      string name;
      int dead,cost;    
    }a[20];
    
    struct dp_s{
      int id,fa;
      int goal;
      int time;
    }dp[1<<16];
    
    int main(){
        int m,n;
        scanf("%d",&m);
        while(m--){
            memset(dp,0,sizeof(dp));
            scanf("%d",&n);
            for(int i=0;i<n;i++){
                cin>>a[i].name>>a[i].dead>>a[i].cost;
            }
            int end=1<<n;
            for(int i=1;i<end;i++){
                dp[i].goal=INF;
                for(int j=n-1;j>=0;j--){                 //从 填充的是最靠后位开始扫描 保证输出的字典序 
                    int cur=1<<j;
                    if(i&cur){                            //二进制扫描 
                        int tem=i-cur;
                        int time=dp[tem].time+a[j].cost;
                        int goal=time-a[j].dead;
                        if(goal<0)goal=0;
                        goal+=dp[tem].goal;
                        if(goal<dp[i].goal){
                            dp[i].goal=goal;
                            dp[i].time=time;
                            dp[i].id=j;
                            dp[i].fa=tem;
                        }
                    }
                    
                }
            }
            vector <int> ans;
            end-=1;
            printf("%d
    ",dp[end].goal);
            while(end)ans.push_back(dp[end].id),end=dp[end].fa;
            for(int i=ans.size()-1;i>=0;i--)cout<<a[ans[i]].name<<endl;
        }
        return 0;
    }
  • 相关阅读:
    shell脚本根据端口号kill掉进程
    使用netstat -ano 查看机器端口的占用情况(windows环境)
    分享一两个小工具,
    将压缩文件伪装图片格式文件以及将python文件转化为exe文件(测试完,真的有效)
    celery 异步任务 周期任务 定时任务的实现
    wsgi、uwsgi、asgi协议的关系
    centos7忘记密码更改步骤
    工作遇到的坑以及自己的学习悟道之道
    案例小集锦
    asp.net mvc部署
  • 原文地址:https://www.cnblogs.com/-ifrush/p/10452268.html
Copyright © 2011-2022 走看看