Week12 作业 E - 选做题(ddl扣分)

一、题目描述
Description

马上假期就要结束了,zjm还有 n 个作业,完成某个作业需要一定的时间,而且每个作业有一个截止时间,若超过截止时间,一天就要扣一分。
zjm想知道如何安排做作业,使得扣的分数最少。
Tips: 如果开始做某个作业,就必须把这个作业做完了,才能做下一个作业。

Input

有多组测试数据。第一行一个整数表示测试数据的组数
第一行一个整数 n(1<=n<=15)
接下来n行,每行一个字符串(长度不超过100) S 表示任务的名称和两个整数 D 和 C,分别表示任务的截止时间和完成任务需要的天数。
这 n 个任务是按照字符串的字典序从小到大给出。

Output

每组测试数据,输出最少扣的分数,并输出完成作业的方案,如果有多个方案,输出字典序最小的一个。

Sample Input

2
3
Computer 3 3
English 20 1
Math 3 2
3
Computer 3 3
English 6 3
Math 6 3

Sample Output

2
Computer
Math
English
3
Computer
English
Math

Hint

在第二个样例中,按照 Computer->English->Math 和 Computer->Math->English 的顺序完成作业,所扣的分数都是 3,由于 English 的字典序比 Math 小,故输出前一种方案。

二、思路概述

  • 用f[S]表示写了S作业,要扣的最少分,用sum[S]表示写了S作业,要花的时间,pre[S]来表示到了S状态,最后更新的作业(用于回溯)。
  • 转移方程
    sum = S 作业集合对应的总时间
    f[S|(1<<x)] = f[S] + tmp(作业 x 被扣的分数)
    c[x] = 作业 x 完成所需时间
    d[x] = 作业 x 的 DDL
    tmp = max ( sum + c[x] – d[x], 0 )
  • 枚举每一个作业总和S,对每一个S,枚举它里面的每一项作业,看是否能进行转移。

三、细节

  1. 用二进制编码来表示状态的相关操作:
    在这里插入图片描述
    2.对每一个编号为i的点,应该是1<<i来表示这个状态,而不是>>。
    四、完整代码
/*先枚举只写两份作业的最短时间,
再枚举只写三份作业的时间....
最后得到的结果就是写所有作业的时间*/ 
#include<iostream>
#include<algorithm> //fill函数,sort函数,max函数 
#include<set>//set函数,(去除重复) 
#include<map>//不同类型转换 
#include<cstring>//memset函数 
using namespace std;
const int inf=1e9;
int f[50010],sum[50010],pre[50010];//f[S]表示在S这一状态下扣的最少分 t[S]表示花的时间 

struct hwork{
	string name;
	int time;
	int ddl;
}hw[20];

void output(int s){
	if(s==0)return;
	//cout<<"yes"<<endl;
		output(s-(1<<pre[s]));
		cout<<hw[pre[s]].name <<endl;
	
	
}
int main(){
	int n;cin>>n;
	while(n--){
		
		int m;cin>>m;
		memset(f,0,sizeof(f));
		memset(sum,0,sizeof(sum));
		//memset(sum,0,sizeof(sum));
		for(int i=0;i<m;i++){
			string nm;cin>>nm;hw[i].name=nm;
			int dl;cin>>dl;hw[i].ddl=dl;
			int ti;cin>>ti;hw[i].time=ti;
			//int mm=1<<(i);sum[mm]=ti;		
		}
		
		int num=(1<<m)-1; 
		//cout<<num<<endl;
		for(int s=1;s<=num;s++){//枚举事件的总和S
		   f[s]=inf;//f[s]的值设的很大,便于初始更新
		   //cout<<s<<"s"<<endl;
		   for(int j=m-1;j>=0;j--){//枚举每一件事 
		   	    int x=1<<j;		   	    
		   	    if(!(s&x))continue;//s事件和里面不包括事件j
				int temp=max(sum[s-x]+hw[j].time-hw[j].ddl,0);
				//cout<<sum[s]+hw[j].time-hw[j].ddl<<"temp另外"<<endl;
				//cout<<j<<"j"<<endl;cout<<sum[s]<<"sum"<<endl;
				//cout<<temp<<"temp"<<endl;
				if(f[s]>f[s-x]+temp){
					f[s]=f[s-x]+temp;//事件s最少超时 
					//cout<<f[s]<<endl;
					sum[s]=sum[s-x]+hw[j].time ;//sum里面存的是事件s所用的时间总和
					//cout<<sum[s]<<"sum222222222"<<endl;
					pre[s]=j;//事件的最晚事件是j 
				} 
		   } 
			
		}
		cout<<f[num]<<endl; 
		//cout<<"hellp"<<endl;
		output(num);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL是一种开源的关系型数据库管理系统,它支持多种操作系统,并且广泛应用于Web应用程序的后端数据存储。MySQL的DDL(Data Definition Language)是用于定义和管理数据库结构的基础操作。 以下是MySQL中DDL的基础操作: 1. 创建数据库:使用CREATE DATABASE语句可以创建一个新的数据库。例如,CREATE DATABASE mydatabase; 2. 删除数据库:使用DROP DATABASE语句可以删除一个已存在的数据库。例如,DROP DATABASE mydatabase; 3. 创建表:使用CREATE TABLE语句可以创建一个新的数据表。在CREATE TABLE语句中,需要指定表名和表的列及其属性。例如,CREATE TABLE mytable (id INT, name VARCHAR(50)); 4. 删除表:使用DROP TABLE语句可以删除一个已存在的数据表。例如,DROP TABLE mytable; 5. 修改表结构:使用ALTER TABLE语句可以修改已存在的数据表的结构,包括添加、修改和删除列等操作。例如,ALTER TABLE mytable ADD COLUMN age INT; 6. 添加主键:使用ALTER TABLE语句可以为数据表添加主键约束,以确保每行数据的唯一性。例如,ALTER TABLE mytable ADD PRIMARY KEY (id); 7. 添加外键:使用ALTER TABLE语句可以为数据表添加外键约束,以确保与其他表的关联完整性。例如,ALTER TABLE mytable ADD FOREIGN KEY (customer_id) REFERENCES customers(id); 8. 创建索引:使用CREATE INDEX语句可以为数据表创建索引,以提高查询性能。例如,CREATE INDEX idx_name ON mytable (name); 这些是MySQL中DDL的基础操作,通过这些操作可以定义和管理数据库的结构。如果你有更具体的问题或者需要了解更多高级的DDL操作,请告诉我。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值