題意:有n門功課,每一門需要c天完成,若在d天還沒有完成,之後每一天直到完成,會被扣分數。
一題dp。
用的狀態壓縮,因爲最多15門功課。所以我們可以從1枚舉到1<<15 - 1來代表所有功課的完成情況。比如有三門功課101代表,第一門和第三門完成,而第二門沒有完成。
用&判斷此功課是否在當前枚舉量中存在,若存在,便可尋求當前的最優解和跟新父節點。
每一次狀態的改變都是在枚舉量變化之後,所以從前開始改變功課當前的狀態,還是從後開始,並不影響答案。
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn = 15 + 5;
const int inf = 100000000;
struct node
{
string name;
int dead;
int cost;
}work[maxn];
struct node1
{
int pre, time, cost, now;
}dp[1<<15 + 5];
void print(int n)
{
if(dp[n].pre) print(dp[n].pre);
cout<<work[dp[n].now].name<<endl;
}
int main()
{
int T;
scanf("%d", &T);
for(int kase = 1; kase <= T; kase++)
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
cin>>work[i].name>>work[i].dead>>work[i].cost;
}
int tot = 1<<n;
dp[0].time = 0;
dp[0].cost = 0;
for(int i = 1; i < tot; i++)
{
dp[i].pre = 0;
dp[i].cost = inf;
for(int s = n -1; s >= 0; s--)
{
if(i & (1<<s))
{
// printf("%d %d\n", i, s);
int past = i - (1<<s);
int waste = dp[past].time + work[s].cost - work[s].dead;
if(waste < 0)
waste = 0;
//printf("%d %d\n", past, dp[past].cost);
if(dp[i].cost > dp[past].cost + waste)
{
//printf("%d %d\n", i, waste);
dp[i].cost = dp[past].cost + waste;//更新扣分次數
dp[i].time = work[s].cost + dp[past].time;//更新此狀態的天數
dp[i].pre = past;
dp[i].now = s;
}
}
}
}
printf("%d\n", dp[tot - 1].cost);
print(tot - 1);
}
return 0;
}