説明文
Ignatiusは、30日のACM / ICPCから学校に戻ってきました。今、彼はやるべき多くの宿題を持っています。すべての教師は彼に宿題の提出期限を与えます。Ignatiusが締め切り後に宿題を提出した場合、教師は最終テストのスコアを1日1ポイントずつ減らします。そしてご存知のように、宿題を行うには常に長い時間がかかります。したがって、Ignatiusは、スコアの低下を最小限に抑えるために、宿題の順序を調整できるように支援してほしいと考えています。
入力
入力にはいくつかのテストケースが含まれています。入力の最初の行は、テストケースの数である単一の整数Tです。Tテストケースが続きます。
各テストケースは、宿題の数を示す正の整数N(1 <= N <= 15)で始まります。その後、N行が続きます。各行には、文字列S(被験者の名前。各文字列は最大100文字)と2つの整数D(被験者の期限)、C(この被験者の宿題を完了するまでに何日かかるか)が含まれています。
注:すべての件名はアルファベットの昇順で示されています。したがって、問題をはるかに簡単に処理できます。
出力
各テストケースについて、最小合計スコアの最小値を出力してから、1行に1つずつ、件名の順序を指定する必要があります。複数の注文がある場合は、アルファベットの小さいものを出力する必要があります。
入力例
2
3
コンピューター3 3
英語20 1
数学3 2
3
コンピューター3 3
英語6 3
数学6 3
出力例
2
コンピューター
数学
英語
3
コンピューター
英語
数学
主なアイデア:
Nコースあり、各コースで支払われるD日間があります。彼はC日間を書く必要があり、締め切りが切れる前に1日ごとに控除されます。控除を行うために各コースに割り当てを割り当てる方法を尋ねてください最も低い合計スコア。
分析:
ここでの最大Nは15なので、さまざまなジョブを完了する順序を列挙できることに注意してください。
バイナリ状態圧縮は、現在の状態でのジョブの完了ステータスを記録するために使用されます。たとえば、101は、1番目と3番目のゲートジョブが完了したことを示します。
状態遷移を引き続き検討すると、101は3コースの宿題の完了後に001から変換されるか、または1コースの宿題の完了後に100から変換される可能性があるため、状態遷移は単なる兆候です。
具体的な説明については、コードを参照してください。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 5;
const int INF = 0x3f3f3f3f;
struct node//记录课程作业信息
{
string s;//课程名称
int ddl;//作业deadline
int cost;//作业耗时
}w[20];
struct d//用于DP
{
int time;//该状态下做完指定作业的时间
int score;//该状态下扣除的分数
int pre,now;//用于记录做作业的顺序
}dp[1<<15];
void Print(int state){//打印做作业的顺序
if(!state) return;
Print(dp[state].pre);
cout<<w[dp[state].now].s<<endl;
}
int main() {
int t,n,d,c;
char str[105];
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s %d %d",str,&d,&c);
w[i].s=str;
w[i].ddl=d;
w[i].cost=c;
}
for(int i=1;i<(1<<n);i++){//枚举每个状态
dp[i].score=INF;//初始化扣除的分数为最大值
for(int j=n-1;j>=0;j--){//从后往前枚举到达这一状态时所做的课程作业(做了哪一门课的作业到达这一状态的),为了满足最后输出的顺序为字典最小序
if((i&(1<<j))){//i状态下第j+1门作业已完成
int pstate=i-(1<<j);//第j+1门作业未完成的前一状态
int tmp=dp[pstate].time+w[j+1].cost-w[j+1].ddl;//扣除的分数
if(tmp<0) tmp=0;//扣除的分数不能为负
if(tmp+dp[pstate].score<dp[i].score){//更新i状态下的信息
dp[i].time=dp[pstate].time+w[j+1].cost;
dp[i].score=tmp+dp[pstate].score;
dp[i].now=j+1;//当前刚做完j+1
dp[i].pre=pstate;//记录前一状态
}
}
}
}
cout<<dp[(1<<n)-1].score<<endl;
Print((1<<n)-1);
}
return 0;
}