D:课程大作业
总时间限制:
1000ms
内存限制:
65536kB
描述
小明是北京大学信息科学技术学院三年级本科生。他喜欢参加各式各样的校园社团。这个学期就要结束了,每个课程大作业的截止时间也快到了,可是小明还没有开始做。每一门课程都有一个课程大作业,每个课程大作业都有截止时间。如果提交时间超过截止时间X天,那么他将会被扣掉X分。对于每个大作业,小明要花费一天或者若干天来完成。他不能同时做多个大作业,只有他完成了当前的项目,才可以开始一个新的项目。小明希望你可以帮助他规划出一个最好的办法(完成大作业的顺序)来减少扣分。
输入
输入包含若干测试样例。
输入的第一行是一个正整数T,代表测试样例数目。
对于每组测试样例,第一行为正整数N(1 <= N <= 15)代表课程数目。
接下来N行,每行包含一个字符串S(不多于50个字符)代表课程名称和两个整数D(代表大作业截止时间)和C(完成该大作业需要的时间)。
注意所有的课程在输入中出现的顺序按照字典序排列。
输出
对于每组测试样例,请输出最小的扣分以及相应的课程完成的顺序。
如果最优方案有多个,请输出字典序靠前的方案。
样例输入
2
3
Computer 3 3
English 20 1
Math 3 2
3
Computer 3 3
English 6 3
Math 6 3
样例输出
2
Computer
Math
English
3
Computer
English
Math
提示
第二个测试样例, 课程完成顺序Computer->English->Math 和 Computer->Math->English 都会造成3分罚分, 但是我们选择前者,因为在字典序中靠前.
参考:https://blog.csdn.net/yhjpku/article/details/80698249
分析
有三个地方用到了动归,
一个是计算达到各种可能的状态的最少扣分,状态转移方程dp[i]=min{dp[i^(1<<j)]+koufen[j]}(假设最后一步选择了j);
一个是储存排列顺序;
还有一个是计算到达各种状态的总用时(便于计算当前扣分情况koufen[j]),状态转移方程sumtime[i]=sumtime[i^(1<<j)]+cost[j].
学到
1.组与组之间共用的一些数组不需要memset初始化,因为每次会从基础的开始递推,只需要保证初始值正确,后续的值会进行覆盖。
2."\n"也可以存入字符串里,如此一个简单的<就解决了令人有点头疼的字典序排序
还有
1.位运算熟练
2.优先级:
基本的优先级需要记住:
指针最优,单目运算优于双目运算。如正负号。
先算术运算,后移位运算,最后位运算。请特别注意:1 << 3 + 2 & 7等价于 (1 << (3 + 2))&7.
逻辑运算最后结合。
#include<iostream>
#include<string.h>
#include<string>
using namespace std;
const int MAX=1<<15;
int sumtime[MAX];//达到所表示状态的总用时
int dp[MAX];//达到所表示状态的最少扣分
string arrange[MAX];//每种状态的最佳方案
string name[16];
int ddl[16];
int cost[16];
int cal(int a,int b){
return a<b?0:a-b;
}
int main(){
int T;
cin>>T;
while(T--){
int N;
cin>>N;
for(int i=0;i<N;++i)
cin>>name[i]>>ddl[i]>>cost[i];
int curMax=1<<N;
for(int i=1;i<curMax;++i)
for(int j=0;j<N;++j){
if(i&(1<<j))
{
sumtime[i]=sumtime[i^(1<<j)]+cost[j];
break;
}
}
for(int i=0;i<curMax;++i)
arrange[i]="";
dp[0]=0;
for(int i=1;i<curMax;++i)
for(int j=0;j<N;++j){
if(i&(1<<j)){//到达状态i,最后一步选择的是j
int tmp=dp[i^(1<<j)]+cal(sumtime[i],ddl[j]);
if(arrange[i]==""||tmp<dp[i]||(tmp==dp[i]&&(arrange[i^(1<<j)]+name[j]+"\n")<arrange[i])){
arrange[i]=arrange[i^(1<<j)]+name[j]+"\n";
dp[i]=tmp;
}
}
}
cout<<dp[curMax-1]<<endl;
cout<<arrange[curMax-1];
}
return 0;
}