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
原文地址:https://www.cnblogs.com/edmunds/p/12783786.html