Week12 作业 E

题目描述:

现在有N个作业,每个作业有截止时间和做完该作业需要的时间,如果某个作业在其截止日期之后做完,则扣分,扣的分数等于拖延的时间,问如何调度这N个作业的先后顺序,使得扣的分最少(N<15),多组数据

思路:

  • N=15,不能用N!,能用2^N
  • 状态压缩,把每个作业写没写看成一位,这样就有2^N个状态
  • 记忆化搜索:从全1的状态向前搜索,边界条件是全0的状态,搜的过程中更新每个状态的最小值
  • 最后按状态数组的信息,回溯打印路径

总结:

虽然比HDU-1024简单了一丢丢,但是也折腾了很长时间。

起初想构造一个排列树(从空集开始搜,一直搜到全集),加上最优性剪枝,发现这样不是记忆化搜索(我还以为是),可以画个排列树看一看就发现了

只有从全集开始搜,可能有两条路径搜到同一个集合,这样才是记忆化搜索,也就是从全1搜到全0

如果转成递推也很容易,计算顺序就是先计算集合元素少的,再计算集合元素多的,外层循环应该是从1-N

这里因为懒就不在写递推了,等有时间回顾再写

记忆化搜索代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
int N;
struct HomeWork
{
	string name;
	int	deadLine, needTime;
}H[15];
struct Status	//同一状态的时间是相同的,但是最小分数是需要被更新的
{
	int time;
	int minScore;
}Sta[1<<16];	//一共有1<<16种状态
bool vis[1 << 16];
Status dfs(int now)
{
	if (vis[now]) return Sta[now];
	Sta[now].minScore = INT_MAX;
	vis[now] = 1;
	//找now状态的前导状态
	for (int i = 0; i < N; i++)
	{
		if (now & (1 << i))		//做完第i个作业到达now状态
		{
			Status lastSta = dfs(now - (1 << i));
			int nowTime = lastSta.time + H[i].needTime;
			int nowScore = lastSta.minScore + max(nowTime - H[i].deadLine, 0);
			Sta[now].time = nowTime;
			Sta[now].minScore = min(Sta[now].minScore, nowScore);
		}
	}
	return Sta[now];
}
//判断状态A可否由状态B经过第i个作业转化过来
bool Judge(Status A, Status B, int i)
{
	int Time = B.time + H[i].needTime;
	int Score = B.minScore + max(Time - H[i].deadLine, 0);
	return Time == A.time && Score == A.minScore;
}
void print(int now)
{
	if (now == 0) return;	//边界
	//找now的前导状态,保证字典序逆着找
	for (int i = N-1; i >=0; i--)
	{
		if (now & (1 << i) && Judge(Sta[now], Sta[now - (1 << i)], i))
		{
			print(now - (1 << i));
			cout << H[i].name << endl;
			break;		//注意break
		}
	}
}
int main()
{
	int T; cin >> T;
	while (T--)
	{
		memset(Sta, 0, sizeof(Sta));
		memset(vis, 0, sizeof(vis));
		cin >> N;
		//注意编号从0开始,因为要进行二进制运算
		for (int i = 0; i < N; i++)
			cin >> H[i].name >> H[i].deadLine >> H[i].needTime;
		Sta[0] = { 0,0 };	//起始状态,一个作业都没做,递归边界
		vis[0] = 1;
		Status finalSta = dfs((1 << N) - 1);
		cout << finalSta.minScore << endl;
		print((1 << N) - 1);	
	}
}

  

原文地址:https://www.cnblogs.com/qingoba/p/13050929.html