zoukankan      html  css  js  c++  java
  • hdu1074 状压DP、栈实现记录路径

    题意:给了几门学科作业、它们的截止提交期限(天数)、它们的需要完成的时间(天数),每项作业在截止日期后每拖延一天扣一学分,算最少扣的学分和其完成顺序。

    一开始做的时候,只是听说过状态压缩这个神奇的东西,但事实上我并不会用它,所以白白想了一个晚上没想出来,然后就看了一下题解```再见吧朋友又是新的算法要学了。

    状态压缩,实际上就是用二进制的方式,对于每一个要考察的状态用0/1表示其完成与否,这样当从 1 遍历到 111```111 的时候,就可以遍历完所有的状态了,在遍历的过程中利用位运算以及状态转移就能够最终实现DP。

    首先对于每一个状态 i 初始化其罚分为最大值用于最开始的比较,用 & 运算来判断它的其中某项作业 j 是否已经完成,完成则 & 运算结果为 1 ,否则为 0 ,若已完成,那么考察 j 作业未完成的情况 last ,如果从 last 状态的罚分加上完成作业 j 后的罚分小于当前 i 状态的罚分,则更新 i 状态的罚分情况,并且记录下到 i 状态时做的作业 j 、 i 的上一状态 last 、i 状态的已花费时间,便于进行状态转移和记录路径。最后用栈从全部作业完成时 111`````111 的状态开始通过记录的上一状态往前递推,输出作业次序。

    收获颇丰,但是心力交瘁```代码中间绿绿的是调试的时候用的```因为我蠢```

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stack>
     4 #include<algorithm>
     5 #define INF 1<<30
     6 using namespace std;
     7 struct Sub{
     8     char name[100];
     9     int d,t;
    10 }S[16];
    11 
    12 struct dpl{
    13     int t,s,p,n;
    14 }dp[1<<16];
    15 
    16 int main(){
    17     int T;
    18     while(scanf("%d",&T)!=EOF){
    19         int N;
    20         for(int q=1;q<=T;q++){
    21             scanf("%d",&N);
    22             memset(dp,0,sizeof(dp));
    23             int i,j;
    24             for(i=1;i<=N;i++){
    25                 scanf("%s%d%d",S[i].name,&S[i].d,&S[i].t);
    26             }
    27     /*        for(i=1;i<=N;i++){
    28 
    29             
    30                 printf("%s %d %d",S[i].name,S[i].d,S[i].t);
    31             }*/
    32             int sum=(1<<N)-1,sub,last,pun;
    33     /*        printf("%d ",sum);
    34             while(sum){
    35                 printf("%d",sum&1);
    36                 sum>>=1;
    37             }
    38             printf("
    ");*/
    39             for(i=1;i<=sum;i++){
    40                 dp[i].s=INF;
    41                 for(j=N;j>0;j--){
    42                     sub=1<<(j-1);
    43                     if(i&sub){
    44                         last=i-sub;
    45                         pun=dp[last].t+S[j].t-S[j].d;
    46                         if(pun<0)pun=0;
    47                         if(pun+dp[last].s<dp[i].s){
    48                             dp[i].s=pun+dp[last].s;
    49                             dp[i].t=dp[last].t+S[j].t;
    50                             dp[i].p=last;
    51                             dp[i].n=j;
    52                         }
    53                     }
    54                 }
    55             }
    56             stack<int>s;
    57             int t=sum;
    58             printf("%d
    ",dp[t].s);
    59             while(t){
    60                 s.push(dp[t].n);
    61                 t=dp[t].p;    
    62             }
    63             while(!s.empty()){
    64                 printf("%s
    ",S[s.top()].name);
    65                 s.pop();
    66             }
    67         }
    68     }
    69     return 0;
    70 }
    View Code
  • 相关阅读:
    归并、希尔排序
    堆排序
    [模板] 最小树形图/朱刘算法
    [模板] 常系数线性递推
    [模板] Kruskal算法 && 克鲁斯卡尔重构树
    [模板] 斯特林数,性质以及求法
    这几天想干什么
    奇怪的 Markdown / LaTeX 笔记
    [模板] 各种莫队
    [模板] 2-SAT 问题
  • 原文地址:https://www.cnblogs.com/cenariusxz/p/4286965.html
Copyright © 2011-2022 走看看