• POJ 15288 课程大作业 【状压dp】【字典序输出方案】【北大ACM/ICPC竞赛训练】


     其实这个转移方程比较简单,每次枚举最后一个完成的作业就行了。

    转移方程是 dp[i] = min{ dp[ i - (1<<(k-1))  ] + score(i,k) }

    score(i,k)是完成i这么多作业中最后一个完成的作业是k时,k带来的最小扣分值。

    难点在于字典序输出方案,我建了个ans数组ans[i]代表i状态下最好的完成的最后一个作业。要注意处理字典序的时候,要把从i到0的一整条方案都找到,【因为题目要求的就是如果有最佳方案,输出字典序最小的,而不是要第i个完成的课程字典序较小】,不能光比当前course的字典序。

     1 #include<iostream>
     2 #include<vector>
     3 #include<algorithm>
     4 #define INF 1000000000
     5 using namespace std;
     6 
     7 string course[20];
     8 int deadline[20],c[20],n;
     9 int dp[66000];//dp[i]代表做完【i状态代表的这么多作业】最少扣分 
    10     //dp[0] = 0
    11 int ans[66000];
    12 vector<string> path;
    13 
    14 int finishday(int num){//N代价 
    15     int an=0;
    16     for(int i=1;i<=n;i++){//枚举这种作业完成情况下有没有完成i 
    17         if( num & (1<<(i-1) ) ) an+=c[i]; 
    18     }
    19     return an;
    20 }
    21 
    22 int score(int num,int k){//完成num状态这么多作业,最后一个完成的是k作业,k带来的扣分 
    23     int s = 0;
    24     s = deadline[k] - finishday( num - (1<<(k-1)) ) - c[k];//要扣s分 
    25     if(s>0) s=0;//不用扣分
    26     return -s; 
    27 }
    28 
    29 int main(){
    30     int t; cin>>t;
    31     while(t--){
    32         for(int i=0;i<66000;i++) dp[i]=INF;
    33         cin>>n;
    34         for(int i=1;i<=n;i++) cin>>course[i]>>deadline[i]>>c[i];
    35                 
    36         dp[0]=0;
    37         for(int i=1;i<= (1<<n)-1;i++){//枚举所有的作业完成状态
    38             int best;
    39             for(int k=1;k<=n;k++){//枚举最后一个作业做的是什么
    40                 if( i & (1<<(k-1) ) ) {
    41                     int cnt = dp[ i - (1<<(k-1) ) ] + score(i,k);
    42                     if( cnt<=dp[i] ){
    43                         if( cnt < dp[i] ) best=k;
    44                         else{  
    45                             vector<int> path1,path2;//记录整条路径
    46                             int num = i - (1<<(k-1));
    47                             path1.push_back(k);
    48                             while( ans[num]!=0 ){ int choose = ans[num]; path1.push_back(choose); num-=(1<<(choose-1)); }
    49                             num = i - (1<<(best-1));
    50                             path2.push_back(best);
    51                             while( ans[num]!=0 ){ int choose = ans[num]; path2.push_back(choose); num-=(1<<(choose-1)); }
    52                             
    53                             reverse( path1.begin(),path1.end() );
    54                             reverse( path2.begin(),path2.end() );
    55                             
    56                             if( path1<path2 ) best=k; 
    57                         }//选字典序大的 
    58                         dp[i]=cnt;
    59                     }
    60                 }
    61             }
    62             ans[i]=best;//这种情况下最后一个完成的作业应该是best
    63             //cout<<i<<" "<<best<<endl;
    64         }
    65         
    66         int num = (1<<n) -1; cout<<dp[num]<<endl;
    67         while( ans[num]!=0 ){
    68             int k = ans[num];
    69             path.push_back( course[k] );
    70             num-=(1<<(k-1));
    71         }
    72         for(int i=path.size()-1;i>=0;i--) cout<<path[i]<<endl;
    73         path.clear();
    74     }
    75     
    76     return 0;
    77 }
  • 相关阅读:
    Windows创建多个github git ssh秘钥
    Kafka(三)自动提交存在的问题?
    Kafka(二)关于Kafka设置(spring.kafka.consumer.enable-auto-commit=false)依然提交消息确认的offset问题分析。
    Kafka(一)集群搭建以及常用命令可视化工具
    CPU相关信息操作
    Nginx系列篇
    DB2——临时表
    DB2sql——insert all与insert first用法讲解与实例
    DB2sql——通过查询结果来create table 的3种方式
    DB21019E An error occurred while accessing the directory "/root".
  • 原文地址:https://www.cnblogs.com/ZhenghangHu/p/9369998.html
Copyright © 2020-2023  润新知