狀態壓縮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);
	}
} 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章