HDU-1074 Doing Homework

用状态压缩DP来做
首先最多有15个作业,每个作业有做或者没做两个状态,所以可以用二进制15位整数来表示当前状态
dp的时候就计算要达到当前状态最少扣的分,d[u]=d[去掉第i个作业的状态]+(第i个作业会扣的分)
dp的时候要保存父节点和作业,用来输出
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
using namespace std;
const int N=(1<<15)+10;
const int INF=0x7f7f7f7f;
int n;
string name[16];
int dl[16],cost[16];
int d[N],f[N],op[N];
int dp(int u)
{
	if(d[u]!=-1) return d[u];
	d[u]=INF;
	int vis[16],t=0,temp=u;
	for(int i=n-1;i>=0;i--) //列出哪些作业做了,还有总花费时间
	{
		vis[i]=temp%2;
		temp/=2;
		if(vis[i])
			t+=cost[i];
	}
	for(int i=n-1;i>=0;i--) //从后往前,所以反字典序
		if(vis[i]) //选择做第i个作业
		{
			int v=dp(u-(1<<(n-i-1)));
			if(t>dl[i]) v+=t-dl[i]; //加上当前状态做完第i个作业会扣多少分
			if(v<d[u])
			{
				d[u]=v;
				f[u]=u-(1<<(n-i-1)); //记录父节点
				op[u]=i; //记录作业
			}
		}
	return d[u];
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			cin>>name[i];
			scanf("%d%d",&dl[i],&cost[i]);
		}
		memset(d,-1,sizeof(d));
		d[0]=0;
		printf("%d\n",dp((1<<n)-1));
		stack<int> s;
		int u=(1<<n)-1;
		while(u)
		{
			s.push(op[u]);
			u=f[u];
		}
		while(!s.empty())
		{
			cout<<name[s.top()]<<endl;
			s.pop();
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值