题意:
一行给出科目名称,截止时间,需要的时间,超出截止时间多久就扣多少分,求一个做作业的顺序使扣的分最少,并按字典序打印顺序。科目的名称是按字典序给出的
思路:
状压入门
二进制位表示一个数有没有被取
指的是已做作业结合
的上一个集合,
指由上一个集合到集合
做的是什么作业,
表示到集合
已经过了多久,
就是做了集合
的作业会扣的最少的分。
一个细节点是,每次优先遍历字典序大的作业去得到的状态,这样保证前面选择的作业字典序最小
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;
} 
京公网安备 11010502036488号