Doing Homework HDU - 1074(状压DP)

Doing Homework

题目链接:HDU - 1074
题意:有n科作业需要做, 给出每科作业的名字, 上交时间(最晚完成期限), 完成作业需要的时间;当作业完成时已超过最晚期限, 则每超一天扣一分;让你合理安排时间, 使得扣分最少, 然后输出路径, 如果有多个答案输出字典序最小的;
n的范围是1~15, 一共n!种情况, 扫一遍所有情况明显不靠谱, 想到了状压DP, dp[i]表示状态扣的分, path[i]表示i状态是作path[i]得到的(这就是路径, 最后递归输出),time[i]表示状态已经用了time[i]时间;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=35000;
const int INF=0x3f3f3f3f;
int N;
char s[20][150];
int d[20], t[20];
int dp[maxn], path[maxn], time[maxn];
void print(int x){
	if(x==0) return; 
	print(x-(1<<(path[x]-1)));
	printf("%s\n", s[path[x]]);
}
int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		scanf("%d", &N);
		for(int i=1; i<=N; i++){
			scanf("%s%d%d", s[i], &d[i], &t[i]);
		}
		memset(time, 0, sizeof(time));
		for(int i=1; i<(1<<N); i++){
			dp[i]=INF;
			for(int j=N; j>0; j--){//题目要求字典序最小;
				if((i&(1<<(j-1)))==0) continue;
				int score=time[i-(1<<(j-1))]+t[j]-d[j];
				if(score<=0) score=0;
				if(dp[i]>dp[i-(1<<(j-1))]+score){//因为for循环是N~1,所以这里没有等号,保证字典序最小,若循环变为1~N,这里加上等号;
					dp[i]=dp[i-(1<<(j-1))]+score;
					time[i]=time[i-(1<<(j-1))]+t[j];
					path[i]=j;
				}
			}
		}
		printf("%d\n", dp[(1<<N)-1]);
		print((1<<N)-1);
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/sirius_han/article/details/80327378