- 题目链接 : HDU 1074
- 题意:
- 给出n个课程作业, (课程名称,截止时间,完成所需天数), n<=15
- 每个课程作业,延误一天就扣一分
- 求最少扣分,以及输出方案,按字典序顺序
- 解法:
- n<=15则采用二进制去表示完成状态, 1 < < 15 - 1 = 111 111 111 111 111 (15个1)表示15个任务全部完成,0表示任务未完成,则,状态从 1 到 1 << n -1. 对于状态i而言,如果当前状态中包含第j个任务(即i的二进制位中第j位为1), 则在此条件下, i的前一个状态(没有选择j的状态)为i ^ (1 << j) .故dp[i] = min(dp[i], dp[i^(1 << j)] + dec). 其中dp[i]表示当前状态下,所扣除的分数,dec = now[i^(1 << j)] + cost[j] - deadline[j]. (now[i]表示当前状态下已经经过的天数). 记录下每个状态下所执行的任务.最终递归输出即可.
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i=a; i<=b; ++i)
#define repp(i, a, b) for(int i=b; i>=a; --i)
#define ms(a, b) memset(a, b, sizeof(a));
#define pb push_back
#define mp make_pair
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int, int> pii;
const int maxn=1e5+7, inf = 1e8;
const int m = 1<<15;
struct node{
char name[105];
int de, ne;
}p[maxn];
int dp[m+7], now[m+7], mark[m+7];
void out(int x){
if(!x)return;
out(x-(1<<mark[x]));
printf("%s\n",p[mark[x]].name);
}
int main(){
int t;
scanf("%d", &t);
while(t--){
ms(now, 0);
ms(mark, 0);
int n;
scanf("%d", &n);
rep(i, 0, n-1) {
scanf("%s %d %d", p[i].name, &p[i].de, &p[i].ne);
}
int bits = 1<<n;
rep(i, 1, bits-1){
dp[i] = 1<<20;
repp(j, 0, n-1){
int inx = 1<<j;
if(!(inx & i)) continue;
int dec;
int pre = i^inx;
dec = now[pre] + p[j].ne - p[j].de;
if(dec < 0) dec = 0;
if(dec + dp[pre] < dp[i]){
dp[i] = dec + dp[pre];
now[i] = now[pre]+p[j].ne;
mark[i] = j;
}
}
}
cout << dp[bits-1] <<endl;
out(bits-1);
}
return 0;
}