【D - Doing Homework】

80 篇文章 0 订阅
80 篇文章 0 订阅

思路:

  • 状态压缩 dp
  • 一共十五种课程,我们使用一个整型数的二进制表示已经上过的课程。如000 000 000 000 101(数5)代表当前状态已经上完了第一、三种课程。
  • 其实严格来说,我认为它更多的是一种暴力贪心的思想。因为:我们需要依次从小到大枚举所有的状态,每一种状态都只需要使用已经推过的子状态,并且在其中选择当前最优状态更新自身。
  • 注意:状压 dp都会用到位运算,位运算必须要一步一括号

代码:

  • 核心:
struct SUB{
	//subject
	string name;
	int d;//deadline
	int w;//weight
}sub[20];
struct STATE{
	int reduce;//总扣分 
	int days;//总天数 
	int prestate;//前一状态(整型) 
	int presub;//前一科目(编号) 
}state[maxn];
  • 15ms 1948kB
//15ms		1948kB 


#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack> 
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = (1<<15) + 5;//括号!

int N;
struct SUB{
	//subject
	string name;
	int d;//deadline
	int w;//weight
}sub[20];
struct STATE{
	int reduce;//总扣分 
	int days;//总天数 
	int prestate;//前一状态(整型) 
	int presub;//前一科目(编号) 
}state[maxn];
stack<string> S;

void INIT(){
	memset(state , 0 , sizeof(state));
	for(int i=1;i<maxn;i++){
		//i = 1 
		state[i].reduce = INF;
	}
	return ; 
}

void SOLVE(){
	for(int i=1;i<(1<<N);i++){
		for(int j=N;j;j--){
			int pre = 1<<(j-1);
			if(i & pre){
				int prei = i - pre;
				int reduce = max(0 , state[prei].days + sub[j].w - sub[j].d);
				if(state[prei].reduce + reduce < state[i].reduce){
					state[i].reduce = state[prei].reduce + reduce;
					state[i].days = state[prei].days + sub[j].w;
					state[i].prestate = prei;
					state[i].presub = j;//顺便记录下来,十分方便输出 
					//到这里,发现越界的是做第一件事的格子们,它们的prei = 0,都用到了state[0] 
				}
			}
		}
	}
	return ;
}

void OUTPUT(){
	int cur = (1<<N) - 1;//wdnmd,所有涉及位运算的操作,都必须一步一括号! 
	cout<<state[cur].reduce<<endl;
	while(cur){
		//还没写倒序输出
		int ser = state[cur].presub;//serial
		cur = state[cur].prestate ; 
		S.push(sub[ser].name);//注意要使用提前保存的ser 
	}
	while(S.size()){
		cout<<S.top()<<endl;
		S.pop();
	} 
	return ;
}

int main(){
	int T;cin>>T;
	while(T--){
		INIT();
		cin>>N;
		for(int i=1;i<=N;i++)
			cin>>sub[i].name>>sub[i].d>>sub[i].w;
		SOLVE();
		OUTPUT();
	}
	return 0;
}

二刷:

  • 完全想不起来是状压……
  • cos不能做变量名。
//15ms		3972kB


#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stack>
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = (1<<15) + 5;

int T , N;
struct COURSE{
	string name;
	int D;
	int W;
}co[maxn];
struct DP{
	int pre;
	int day;//已用了多少天
	int penalty;//罚时 
	int preid;
}dp[maxn];

int main(){
	cin>>T;
	while(T--){
		memset(dp , INF , sizeof(dp));
		dp[0].penalty = dp[0].day = dp[0].pre = dp[0].preid = 0;
		cin>>N;
		for(int i=1;i<=N;i++)
			cin>>co[i].name>>co[i].D>>co[i].W;
		for(int i=1;i<(1<<N);i++){
			//当前状态:i 
			int k=1;
			for(int j=1;k<=i;j++ , k<<=1){
				if(k & i){
					int pre = i-k;
					//前一状态:pre
					if(dp[pre].penalty + dp[pre].day + co[j].W - co[j].D <= dp[i].penalty){
						dp[i].penalty = dp[pre].penalty + max(0 , dp[pre].day + co[j].W - co[j].D);
						dp[i].day = dp[pre].day + co[j].W;
						dp[i].pre = pre;
						dp[i].preid = j;
					}
				}
			}
		}
		int cur = (1<<N)-1;
		cout<<dp[cur].penalty<<endl;
		stack<string> S;
		while(cur){
			int id = dp[cur].preid;
			S.push(co[id].name);
			cur = dp[cur].pre;
		}
		while(S.size()){
			cout<<S.top()<<endl;
			S.pop();
		}
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值