HDU1074【状压DP】
2015-09-02 10:05
267 查看
最多15个作业,如果全排列则共有15!种,但是这样会计算很多重复的值,用状压DP,遍历2^15,可以枚举所有作业的出现顺序,并且通过记录,可以进行递推。
初始状态是0,最后的状态是2^16-1(111111....)表示所有的作业都已经做过了。
初始状态是0,最后的状态是2^16-1(111111....)表示所有的作业都已经做过了。
#include <stdio.h> #include <iostream> #include <string.h> #include <algorithm> #include <string> using namespace std; #define maxn 65538 #define inf 999999 class node { public: int dead,spen; string s; }que[22]; class nodee { public: int pre,day,sum; }dp[maxn]; int cmp[maxn],vis[maxn]; void init() { for(int i=0;i<16;i++) cmp[1<<i]=i; } void drawBack(int n) { int a[20],top=0; for(int i=n;i!=-1;i=dp[i].pre) { int pre=dp[i].pre; if(pre==-1) break; int tmp=i^dp[i].pre; tmp=cmp[tmp]; a[top++]=tmp; } for(int i=top-1;i>=0;i--) cout<<que[a[i]].s<<endl; } int main() { int n; init(); int T; cin>>T; while(T--) { cin>>n; memset(vis,0,sizeof(vis)); for(int i=0;i<n;i++) { cin>>que[i].s>>que[i].dead>>que[i].spen; } dp[0].pre=-1; dp[0].day=0; dp[0].sum=0; int maxnum = 1<<n; for(int i=0;i<maxnum;i++) { for(int j=0;j<n;j++) { int k=1<<j; if((i&k)==0) { int neww=i|k; int tmp=que[j].spen+dp[i].day; int sum=dp[i].sum; if(tmp>que[j].dead) sum+=tmp-que[j].dead; if(vis[neww]) { if(sum<dp[neww].sum) { dp[neww].sum=sum;dp[neww].pre=i;dp[neww].day=tmp; } else if(sum==dp[neww].sum) { if(i<dp[neww].pre) dp[neww].pre=i; } } else { vis[neww]=1; dp[neww].sum=sum;dp[neww].pre=i;dp[neww].day=tmp; } } } } cout<<dp[maxnum-1].sum<<endl; drawBack(maxnum-1); } return 0; }
相关文章推荐
- hdu4465 Candy(快速排列组合+概率)
- 谈谈写程序与学英语
- 协议和代理的理解及使用
- jQuery事件绑定—on()、bind()与delegate()
- 详解基于Binder的BroadcastReceiver && 基于Handler的LocalBroadcastManager
- Android中SQLite应用详解
- 如何用CSS画三角形
- shell常用语句
- Android APK反编译就这么简单 详解(附图)
- 1046. Shortest Distance (20)
- easyUI实现显示“未找到查询结果”以及在loadtable方法中传递参数
- 结构体内存大小总结
- 逻辑思维以及最简化
- Effective C++ 改善程序与设计的55个具体做法 读书笔记
- 【tarjan模板】
- 程序员应该避免的5种代码注释
- 最大公共子串(算法)
- 排序算法
- 一个新手对where和left join的疑惑
- PhpExcel中文帮助手册|PhpExcel使用方法