状压DP
来源:互联网 发布:数据库设计与开发规范 编辑:程序博客网 时间:2024/05/21 19:26
HDU1074,这题的大意是一个人需要完成他的作业,但是他的老师给他定了期限,每超过期限一天,就扣一分,问你如何安排做作业的顺序,才能使扣的分数最少,输出要扣的最小分数,并输出完成作业的顺序。(科目数目n<=15)
如果把n个科目进行排序,那么复杂度就有n!,肯定爆炸。其实每一个状态对于一种科目,只有两种可能,一是这个状态下做这个科目,二是不做这个科目,就是1,0两种状态,这样,我们就可以利用二进制很轻松的表示出来(比如101就是这个状态已经做了第一个科目和第三个科目)。利用二进制把状态用0,1表示,就是所谓的状态压缩,用这种方法,我们就可以在(2^n)*n的复杂度下解决这个问题,我们可以明显的看出,状态压缩一般也只能解决n<=15的问题,再大的话,时间也是不够的。
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int maxn = (1<<15) + 5;int dp[maxn];int d[20],f[20];//数组d是期限,数组f是完成需要的时间int pre[maxn],t[maxn];//数组pre是用来记录当前状态是由哪个状态推过来的,数组t是记录到当前状态用了多长时间char a[20][110];void output(int x){ if(!x) return; output(x-(1<<pre[x])); printf("%s\n",a[pre[x]]);}int main(void){ int T,n,m,i,j,inf = 1e9; scanf("%d",&T); while(T--) { scanf("%d",&n); for(i=0;i<n;i++) scanf("%s %d %d",a[i],&d[i],&f[i]); m = 1<<n; for(i=1;i<m;i++)//状态0表示一个科目都没完成,状态2^n-1表示全部科目都已完成 { dp[i] = inf; for(j=n-1;j>=0;j--) { int tem = 1<<j;//表示第j个科目 if((tem&i) == 0)//如果状态i还没有完成j,肯定不能由i-j推过来 continue; int s = t[i-tem] + f[j] - d[j];//表示扣的分数 if(s < 0)//扣的分数最小为0 s = 0; if(dp[i] > dp[i-tem] + s) { dp[i] = dp[i-tem] + s; t[i] = t[i-tem] + f[j]; pre[i] = j; } } } printf("%d\n",dp[m-1]); output(m - 1);//这里用了递归的方法进行输出 } return 0;}/*
input:
2
3
Computer 3 3
English 20 1
Math 3 2
3
Computer 3 3
English 6 3
Math 6 3
output:
2
Computer
Math
English
3
Computer
English
Math
*/
0 0
- 状压dp
- 状压dp
- 状压dp
- 状压DP
- 状压DP
- 状压DP
- 状压dp
- 状压DP
- 状压DP
- 状压dp
- 状压dp
- 状压dp
- 状压DP
- 状压DP
- 状压DP
- 状压DP
- hdu 4336 概率DP 状压DP
- uva 11600 期望dp 状压dp
- 队列简要实现,是queue,不是dequeue
- hiho 40 ->三分·三分求极值
- Android 事件总线OTTO用法快速入门
- Linux makefile 教程 非常详细,且易懂
- php生成艺术签名 下
- 状压DP
- POJ 3468 A Simple Problem with Integers -
- hdu 1426 Sudoku Killer(数独 dfs)
- POJ-3270 Cow Sorting
- 杭电ACM 2087
- C++延时循环的创建
- 开发日记——手机安全卫士 Day02 2016-7-21 完成导航页面和切换功能
- Java程序员们最常犯的10个错误(转载)
- LeetCode-94:Binary Tree Inorder Traversal