hdu 1074 DFS+状态压缩DP
2011-04-22 16:43
316 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1074
题意描述:小m现在需要完成 n (n<15)门课程的作业,每个作业都有截止时间还有完成该作业的天数,若完成作业的时间超过了截止时间,则会被扣分,超出1天扣1分,题目按字典序升序输入所有的作业名,现在需要你输出完成作业的顺序,以使得被扣除的分数最少。 如果存在多种方案,则按字典序最小的输出。
解题思路:完成同样的作业,如果安排的顺序不一样,被扣除的分数也就不一样,但是需要的时间是一样的。所以我们可以通过压缩状态(2进制映射成10进制)来进行最优解剪枝,题目的n<15,采用2进制进行压缩,1表示已完成,0表示未完成。若有3门作业,那么状态110,则表示,第1,2门作业完成,第3门作业未完成,映射为10进制数则为"6"。状态"6"对应有两种不同完成作业的顺序,一种,先完成第1门,再完成第2门。另一种,先完成第2门,再完成第1门。搜索过程都取最优解。题目要求若存在多种方案,要按字典序最小的输出,又因为题目输入的是用字典序升序输入,所以对于同样的状态state,若他们有同样的状态值hash[state],先搜索到的字典序肯定比后搜索到的字典序小。所以在更新最优解的时候,只需要用严格"<"号来判断是否更新最优解即可保证多个方案下能得到字典序最小的。
题意描述:小m现在需要完成 n (n<15)门课程的作业,每个作业都有截止时间还有完成该作业的天数,若完成作业的时间超过了截止时间,则会被扣分,超出1天扣1分,题目按字典序升序输入所有的作业名,现在需要你输出完成作业的顺序,以使得被扣除的分数最少。 如果存在多种方案,则按字典序最小的输出。
解题思路:完成同样的作业,如果安排的顺序不一样,被扣除的分数也就不一样,但是需要的时间是一样的。所以我们可以通过压缩状态(2进制映射成10进制)来进行最优解剪枝,题目的n<15,采用2进制进行压缩,1表示已完成,0表示未完成。若有3门作业,那么状态110,则表示,第1,2门作业完成,第3门作业未完成,映射为10进制数则为"6"。状态"6"对应有两种不同完成作业的顺序,一种,先完成第1门,再完成第2门。另一种,先完成第2门,再完成第1门。搜索过程都取最优解。题目要求若存在多种方案,要按字典序最小的输出,又因为题目输入的是用字典序升序输入,所以对于同样的状态state,若他们有同样的状态值hash[state],先搜索到的字典序肯定比后搜索到的字典序小。所以在更新最优解的时候,只需要用严格"<"号来判断是否更新最优解即可保证多个方案下能得到字典序最小的。
#include <iostream> #include <string> #include <algorithm> using namespace std; const int MAXN = 32768 + 100; const int INF = 0x3fffffff; int hash[MAXN]; int pow[17] = {0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384}; int n; int temp[20]; //记录临时方案 int used[20]; int save[20]; //记录最终方案 int ans; struct Homework { string name; //课程名 int deadline; //截止时间 int days; //完成作业需要的天数 }; Homework hw[16]; void init() { memset(hash,-1,sizeof(hash)); memset(used,0,sizeof(used)); ans = INF; } //参数:编号为k的作业,完成k号作业的hash状态,完成k号作业后的日期now,被扣除的学分sum,完成了cnt门作业 void dfs(int k,int state, int now, int sum, int cnt) { if(cnt == n) //完成全部的作业 { if(sum < ans) //如果用"<="取代"<",那么输出的结果就不一定是字典序最小的顺序 { ans = sum; for(int i=0; i<n; i++) //保存最优解 { save[i] = temp[i]; } return ; } } if(hash[state] != -1 && sum > hash[state]) //最优解剪枝 { return ; } if(hash[state] == -1 || sum < hash[state]) //更新最优解 { hash[state] = sum; } for(int i=1; i<=n; i++) //遍历所有作业 { if(!used[i]) { int tempNow,tempSum; //回溯后需要恢复now和temp,所以在这里我用多2个新变量,而不去改变now和temp的值 if(now + hw[i].days > hw[i].deadline) { tempSum = sum + now + hw[i].days - hw[i].deadline; } else { tempSum = sum; } tempNow = now + hw[i].days; used[i] = 1; temp[cnt] = i; dfs(i,state+pow[i],tempNow,tempSum,cnt+1); used[i] = 0; //回溯解除标记 } } } int main() { int t; int i; cin>>t; while(t--) { init(); cin>>n; for(i=1; i<=n; i++) { cin>>hw[i].name>>hw[i].deadline>>hw[i].days; } dfs(0,0,0,0,0); cout<<ans<<endl; for(i=0; i<n; i++) { cout<<hw[save[i]].name<<endl; } } return 0; }
相关文章推荐
- HDU 1074 Doing Homework【状态压缩DP】
- HDU1074 Doing Homework 状态压缩dp
- HDU-1074 Doing Homework 状态压缩DP
- hdu 1074 Doing Homework(状态压缩DP)
- hdu 1074 状态压缩dp
- HDU 1074 Doing Homework(状态压缩DP)
- HDU 1074 状态压缩DP
- HDU 4272LianLianKan 2012长春网络赛F题(思维) 暴力,dfs可以水过,正解是状态压缩dp
- hdu1074 状态压缩dp 记录路径
- hdu 3681 Prison Break (状态压缩dp/dfs + bfs)
- hdu1074 状态压缩DP
- HDU 1074 Doing Homework (状态压缩DP+位运算)【一维状压--期限类模板】
- hdu 1074 状态压缩DP 贪心 错的原因
- HDU 1074 Doing Homework(状态压缩dp)
- HDU 1074 Doing Homework(状态压缩DP)
- HDU 1074 Doing Homework 状态压缩+DP .
- HDU 1074【状态压缩DP】
- hdu1074 Doing Homework (状态压缩dp)
- hdu1074 状态压缩dp 记录路径
- HDU 1074(dp46)(状态压缩dp)