题意:
一行给出科目名称,截止时间,需要的时间,超出截止时间多久就扣多少分,求一个做作业的顺序使扣的分最少,并按字典序打印顺序。科目的名称是按字典序给出的
思路:
状压入门
二进制位表示一个数有没有被取
指的是已做作业结合的上一个集合,指由上一个集合到集合做的是什么作业,表示到集合已经过了多久,就是做了集合的作业会扣的最少的分。
一个细节点是,每次优先遍历字典序大的作业去得到的状态,这样保证前面选择的作业字典序最小
Code:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include <vector> #include<map> #include<set> #include<utility> using namespace std; typedef long long ll; inline ll read() { ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } string s[15]; int d[15],need[15]; struct node{ int pos,last,now,cost; }dp[1<<15]; void print(int x) { if(!x) return; print(dp[x].last); cout<<s[dp[x].pos]<<endl; } int main() { int t=read(),n; while(t--) { n=read(); for(int i=0;i<n;++i) { cin>>s[i]; d[i]=read(),need[i]=read(); } dp[0].last=dp[0].now=0; for(int i=1,last,tmp,l;i<(1<<n);++i) { dp[i].cost=0x3f3f3f3f; for(int j=n-1;j>=0;--j) { l=1<<j; if(i&l) { last=i-l; tmp=dp[last].now+need[j]-d[j]; if(tmp<0) tmp=0; if(tmp+dp[last].cost<dp[i].cost) { dp[i].cost=dp[last].cost+tmp; dp[i].last=last; dp[i].now=dp[last].now+need[j]; dp[i].pos=j; } } } } printf("%d\n",dp[(1<<n)-1].cost); print((1<<n)-1); } return 0; }