状态压缩dp-HDU1074-Doing Homework

题目: 

  每门课的作业有截止日期和完成作业所需要的日期, 然后有多门课,如果每门课没完成会有一个惩罚,惩罚为多出来的时间。 求做作业的顺序,使得惩罚最小。

有T组数据, 每组数据 给出N门课,每门课给出了S(课程名) D(截止日期) C(完成作业所需的时间)

思路:

  课的总数 <= 15, 设dp[i]  为状态i时候最优解的值, 然后状态i可以通过状态j转移过来,条件是i中至少含有一个j中没有的1。 然后就枚举所有的i中的1, dp[i] = dp[j] + cost[i<-j], 但是这个时候可能需要 惩罚 ,可能不需要惩罚。dp[i] = dp[j] + max(0,last[i] + cost[i<-j] - d[i<-j])


代码:

#include <cstring>
#include <stdio.h>
#include <iostream>
using namespace std;

int Case;
int n;
const int maxn = 21;
int d[maxn];
int t[maxn];
int pre[1 << 16];
char name[maxn][160];
int dp[1 << 16];
int time[1 << 16];

void print(int state) {
	if(state == 0) return ;
	print(pre[state]);
	
	state -= pre[state];
	for(int i=0;i<n;i++) {
		if(state & (1 << i)) {
			puts(name[i]);
		}
	}
}
int main() {
	
	freopen("in.txt","r",stdin);
	scanf("%d",&Case);
	while(Case--) {
		scanf("%d",&n);
		for(int i=0;i<n;i++) {
			scanf("%s%d%d",name[i],&d[i],&t[i]);
		} 
		memset(dp,0x3f,sizeof(dp));
		dp[0] = 0;
		memset(time,0,sizeof(time));
		memset(pre,0,sizeof(pre));
		int upp = 1 << n;
		for(int i=1;i < upp;i ++) {
			for(int j=0;j<n;j++) {
				if((i & (1 << j)) == 0) {
				 	continue;
				}
				int prestate = i - (1 << j);
				time[i] = time[prestate] + t[j];
				int cost = max(0,time[prestate]+t[j] - d[j]);
				if(dp[prestate] + cost <= dp[i]) {
					dp[i] = dp[prestate] + cost;
					pre[i] = prestate;
				}
			} 
		}
		printf("%d\n",dp[upp-1]); 
		print(upp-1);
	}
} 


你可能感兴趣的:(动态规划,状态压缩)