您的位置:首页 > 其它

HDU 1074 Doing Homework(DP状态压缩)

2018-05-14 18:01 363 查看

题意:有n门功课需要完成,每一门功课都有时间期限以及你完成所需要的时间,如果完成的时间超出时间期限多少单位,就会被减多少学分,问以怎样的功课完成顺序,会使减掉的学分最少,有多个解时,输出功课名字典序最小的一个。

作业最多只有15个,容易想到是状态压缩  dp[i]表示i对应状态的最小扣分  i转换为二进制后为1的位表明该位对应的作业已经做了,为0的位没做。

dp[i] = min{dp[k] + cost | k为将某一位变成1后等于 i 的状态} 

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 16;
struct Node
{
char str[109];
int want, need;
}node
;

struct DP // 状态
{
int now, sum, pre, pos; // 当前状态的时间,总惩罚,前一个选择,当前选择
}dp[1<<N];

void put_ans(int x)
{
if(dp[x].pre != -1)
{
put_ans(dp[x].pre);
printf("%s\n", node[dp[x].pos].str);
}
}

int main () {

int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%s%d%d", node[i].str, &node[i].want, &node[i].need);
dp[0].now = dp[0].sum = 0;
dp[0].pre = dp[0].pos = -1;
int m = (1<<n)-1;
for(int i=1; i<=m; i++)
{
dp[i].sum=0x3f3f3f3f;
for(int j=0; j<n; j++)
{
if((1<<j) & i)
{
int k = i - (1<<j);
int v = dp[k].now + node[j].need - node[j].want;
v = max(v, 0);
if(dp[i].sum >= dp[k].sum+v)//必须有等号,这样保持字典序
{
dp[i].sum = dp[k].sum + v;
dp[i].now = dp[k].now + node[j].need;
dp[i].pre = k;
dp[i].pos = j;
}
}
}
}
printf("%d\n", dp[m].sum);
put_ans(m);
}
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: