zoukankan      html  css  js  c++  java
  • hdoj1074--Doing Homework (DP 状态压缩)

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

    思路:

    看着数据很小,15,但是完成的顺序有15!情况,这么大的数据是无法实现的。上网查才知道要用状态压缩,用二进制表示状态,比如n=3时:111表示3門全部完成,011表示完成第1,2門的状态,000表示一門都没完成的情况。这样压缩之后最多就只有1<<15种状态了,然后直接dp就可以了。大体思路是从1状态到(1<<n-)1依次遍历,寻找上一个状态,使得到达此状态时总扣分最小,寻找上一个状态时j从n-1开始到0倒着遍历,这样才能保证最终结果是字典序最小的,这里要仔细想一下,比如寻找111的上一个状态,若j=1和j=0对应的上一个状态同时使111这个状态的总扣分最小,因为输入的顺序即按字典序来的,所以j=1对应的作业字典序要大于j=0的,所以要让j=0对应的作业先于j=1的完成,所以应该选择j=1作为上一个状态,故应该倒着遍历。详见代码。

    AC代码如下:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int inf=0x3f3f3f3f;
     5 struct course{
     6     char name[105];
     7     int d,c;
     8 }a[20];
     9 
    10 struct node{  //上一个状态,扣分值,总用时,该状态所做的作业编号
    11     int pre,redu,cost,cou;
    12 }dp[1<<15+5];
    13 
    14 int T,n,maxn;
    15 
    16 void print(int p){   //递归逆向输出
    17     if(p){
    18         print(dp[p].pre);
    19         printf("%s
    ",a[dp[p].cou].name);
    20     }
    21 }
    22 
    23 int main(){
    24     scanf("%d",&T);
    25     while(T--){
    26         scanf("%d",&n);
    27         maxn=1<<n;    
    28         for(int i=0;i<n;i++)
    29             scanf("%s%d%d",a[i].name,&a[i].d,&a[i].c);
    30         memset(dp,0,sizeof(dp));
    31         for(int i=1;i<maxn;i++){
    32             dp[i].redu=inf;    //找最小的扣分,所以初始化为inf
    33             for(int j=n-1;j>=0;j--){   //倒着遍历,为了结果字典序最小
    34                 int t=1<<j;
    35                 if(i&t){
    36                     int tmp=i-t;    //上一个状态
    37                     int tt=dp[tmp].cost+a[j].c-a[j].d;
    38                     if(tt<0) tt=0;  //扣分值若小于0则置0
    39                     if(dp[tmp].redu+tt<dp[i].redu){
    40                         dp[i].redu=dp[tmp].redu+tt;
    41                         dp[i].pre=tmp;
    42                         dp[i].cost=dp[tmp].cost+a[j].c;
    43                         dp[i].cou=j;
    44                     }
    45                 }
    46             }
    47         }
    48         printf("%d
    ",dp[maxn-1].redu);
    49         print(maxn-1);
    50     }
    51     return 0;
    52 }
  • 相关阅读:
    PAT B1027 打印沙漏 (20 分)
    PAT B1025 反转链表 (25 分)
    PAT B1022 D进制的A+B (20 分)
    PAT B1018 锤子剪刀布 (20 分)
    PAT B1017 A除以B (20 分)
    PAT B1015 德才论 (25 分)
    PAT B1013 数素数 (20 分)
    PAT B1010 一元多项式求导 (25 分)
    HDU 1405 The Last Practice
    HDU 1165 Eddy's research II
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/10389580.html
Copyright © 2011-2022 走看看