• hdu1074 doing homework


    题目链接:https://vjudge.net/problem/HDU-1074

    状压dp。将作业从0-n-1存储。对于二进制m位为1表示做了第m门作业(右一位定义为第0位)。可以写出转移方程:f[i]=min(f[st]+max(time-a[j].d,0)),此处st表示如果状态i的j位为1也就是做了第j门作业时,将第j位的1变为0的状态。也就是表示最后做的作业为j之前所需要花费的代价+做完作业j后产生的代价中取最小值,time表示做j之前其他作业产生的总时间,可以遍历st的二进制位计算得出。这样已经可以求出最小时间即为f[(1<<n)-1]

    对于字典序最小方案的打印,一开始认为既然作业名称已经按照字典序排序了,每次回溯的时候总是找到更靠前的状态更好。虽然在vjudge上过了(数据有点水?),但在hdu上发现了hack数据。脑补一下字典序的比较方法,感觉不一定是对的?因为这只能保证回溯的那一个位置取更小的字典序,并不能保证整个的字典序最小。于是干脆把所有解都列举了出来比较字典序(见代码),在vjudge上也过了......

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 struct hw{
     4     string s;
     5     int d,t;
     6 }a[20];
     7 const int inf=0x3f3f3f3f;
     8 int f[1<<17],c[1<<17];
     9 string s[20],ans[20];
    10 int n,i,j,m,tt,k;
    11 
    12 void dfs(int i,int l){
    13     if (i==0) {
    14         if (ans[0]=="") for (int j=0;j<n;j++) ans[j]=s[j];        
    15         int f=0;
    16         for (int j=0;j<n;j++) 
    17           if (s[j]!=ans[j]){
    18               if (s[j]<ans[j]) f=1;
    19               break;
    20           }
    21         if (f==1) for (int j=0;j<n;j++) ans[j]=s[j];
    22     }
    23     int st;
    24     for (int j=n-1;j>=0;j--){
    25       if ((i>>j)&1){
    26           st=i&(~(1<<j));
    27           if (f[st]+max(c[i]-a[j].d,0)==f[i]) {
    28               s[l]=a[j].s;
    29               dfs(st,l-1);
    30           }                             
    31        }
    32     }
    33 }
    34 
    35 int main(){
    36     //freopen("hdu1074.txt","r",stdin);
    37     cin>>tt;
    38     while (tt--){
    39         cin>>n;
    40         for (i=0;i<n;i++) cin>>a[i].s>>a[i].d>>a[i].t;
    41         memset(f,0,sizeof(f));
    42         memset(c,0,sizeof(c));
    43         for (i=0;i<n;i++) ans[i]=s[i]="";
    44         for (i=1;i<=(1<<n)-1;i++){
    45             f[i]=inf;
    46             for (j=0;j<n;j++) if ((i>>j)&1) c[i]+=a[j].t;
    47             for (j=0;j<n;j++)
    48               if ((i>>j)&1){
    49                   int st=i&(~(1<<j));
    50                   int time=a[j].t;
    51                                 for (k=0;k<n;k++) if ((st>>k)&1) time+=a[k].t;
    52                   f[i]=min(f[i],f[st]+max(time-a[j].d,0));
    53               }
    54         }
    55         cout<<f[(1<<n)-1]<<endl;
    56         dfs((1<<n)-1,n-1);
    57         for (int j=0;j<n;j++) cout<<ans[j]<<endl;
    58     }
    59     //fclose(stdin);
    60     return 0;
    61 }
    hdu1074
  • 相关阅读:
    抓老鼠啊~亏了还是赚了?
    币值转换
    打印沙漏
    秋季学习总结
    对我影响最大的三位老师
    自我介绍
    第三周作业
    第二周作业
    求最大值及其下标
    PTA编程总结3
  • 原文地址:https://www.cnblogs.com/edmunds/p/12783786.html
Copyright © 2020-2023  润新知