参考:http://www.cnblogs.com/kuangbin/archive/2011/08/04/2127687.html
膜拜斌巨orz
算法核心:状态压缩DP
大意:
有n门课程作业,每门作业的截止时间为D,需要花费的时间为C,若作业不能按时完成,每超期1天扣1分。
这n门作业按课程的字典序先后输入
问完成这n门作业至少要扣多少分,并输出扣分最少的做作业顺序
PS:达到扣分最少的方案有多种,请输出字典序最小的那一组方案
分析:
n<=15,由题意知,只需对这n份作业进行全排列,选出扣分最少的即可。
用一个二进制数存储这n份作业的完成情况,第1.。。。n个作业状况分别
对应二进制数的第0,1.。。。。,n-1位则由题意,故数字上限为2^n
其中 2^n-1即为n项作业全部完成,0为没有作业完成。。。
用dp[i]记录完成作业状态为i时的信息(所需时间,前一个状态,最少损失的分数)。
递推条件如下
1.状态a能做第i号作业的条件是a中作业i尚未完成,即a&i=0。
2.若有两个状态dp[a],dp[b]都能到达dp[i],那么选择能使到达i扣分小的那一条路径,若分数相同,转入3
3.这两种状态扣的分数相同,那么选择字典序小的,由于作业按字典序输入,故即dp[i].pre = min(a,b);
初始化:dp[0].cost = 0;dp[0].pre=-1;dp[0].reduced = 0;
最后dp[2^n-1].reduced即为最少扣分,课程安排可递归的输出
/* *********************************************** Author :devil Created Time :2015/12/9 17:19:27 ************************************************ */ #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <map> #include <set> #include <vector> #include <cstdio> using namespace std; const int N=1<<16; bool vis[N]; struct wq { int pre,cost,lost;//前一状态,所需状态,最少损失的分数 } dp[N]; struct we { int dead,cost;//截止日期,所需日期 char name[105]; } c[16]; void init() { memset(vis,0,sizeof(vis)); dp[0].cost=0; dp[0].pre=-1; dp[0].lost=0;//dp[0]是指所有作业都没有做的状态 vis[0]=1; } void output(int now) { int work=dp[now].pre^now,id=-1; while(work) { id++; work>>=1; } if(dp[now].pre) output(dp[now].pre); printf("%s ",c[id].name); } int main() { //freopen("in.txt","r",stdin); int t,n; scanf("%d",&t); while(t--) { init(); scanf("%d",&n); for(int i=0; i<n; i++) scanf("%s%d%d",c[i].name,&c[i].dead,&c[i].cost); int upper=(1<<n)-1;//tupper表示成二进制数是n个1的,表示所有的作业都完成了 for(int i=0; i<upper; i++)//遍历所有状态 { for(int work=0; work<n; work++)//遍历所有作业 { int cur=1<<work; if(!(cur&i))//该项作业尚未做过 { int curtemp=cur|i; int day=dp[i].cost+c[work].cost; dp[curtemp].cost=day; int reduce=day-c[work].dead; if(reduce<0) reduce=0; reduce+=dp[i].lost; if(vis[curtemp])//该状态已有访问信息 { if(reduce<dp[curtemp].lost) { dp[curtemp].lost=reduce; dp[curtemp].pre=i; } } else//没有访问过 { vis[curtemp]=1; dp[curtemp].lost=reduce; dp[curtemp].pre=i; } } } } printf("%d ",dp[upper].lost); output(upper);//递归输出 } return 0; }