状压dp -- Doing Homework HDU - 1074

Doing Homework HDU - 1074

题意:
有n门课程的作业,每门作业都有截止时间和做作业花费时间,当到截至时间该作业还没做完时会扣除延期时间数量的分数,问按怎样的顺序来做扣除的总分数最短,输出最短时间,完成作业的顺序(按字典序输出)。

思路:
状态压缩作业的完成情况,二进制位上的1表示对应作业完成,共有(1 << n)- 1种作业状态,从1到 (1 << n)- 1dp过去,状态转移式为:
p[i].dp = min( p[i].dp, p[i ^ (1 << j)].dp + min(0, start[j] - p[i ^ (1 << j)].time - cost[j]) )。
p[i].dp表示状态i的总扣分,start[j]表示课程j的截至时间,cost[j]表示完成课程j要花费的时间。

code:


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<stack>
#include<cmath>
#include<algorithm>
using namespace std; 
const int maxn = 1e5 + 5;
const int inf = 1e8 + 5;
struct node{
	int time, dp, pre, ind;  //完成目前状态作业花的时间, 扣分, 记录最优转移前继节点,当前作业
} p[maxn];

void init(int n){
	for(int i = 0; i <= n; i++){
		p[i].dp = inf;
	}
}
int main(){
	int T, n, start[20], cost[20];
	char s[20][105];
	scanf("%d", &T);
	while(T--){
		scanf("%d", &n);
		
		init(1 << n);
		
		for(int i = 0; i < n; i++)
			scanf("%s%d%d", s[i], &start[i], &cost[i]);
			
		p[0].dp = p[0].time = 0;  //处理边界值
		for(int i = 1; i < 1 << n; i++){
			
			for(int j = n - 1; j >= 0; j--){
				
				if(i & (1 << j)){
					int num = i ^ (1 << j);
					int sum = max(0, p[num].time + cost[j] - start[j]);
					if(p[i].dp > p[num].dp + sum){   //状态转移
						p[i].dp = p[num].dp + sum;  
						p[i].time = p[num].time + cost[j];
						p[i].ind = j;
						p[i].pre = num;
					}
				} 
			}		   
		}
		
		stack<int> st;
		while(st.size()) st.pop();
		int x = (1 << n) - 1;
		while(x != 0){
			st.push(p[x].ind);
			x = p[x].pre;
		}
		printf("%d\n", p[(1 << n) - 1].dp);
		while(st.size()){
			x = st.top();
			st.pop(); 
			printf("%s\n", s[x]);
		}
		
		
	}
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值