算法练习系列—hiho1044 状态压缩二(捡垃圾)

题目地址http://hihocoder.com/problemset/problem/1044

算法思路:此题可以看做是铺地砖的变形,没有明显的行数和状态,但是我们可以自己将其中的行和状态给扣出来。其中第一行就是N个数的中前(0,1,2…M-1), 第二行就是(2,3..M)…一直到最后一行为(N-M…N)。每一行的状态个数即为2^M-1(即这M个位置要么填写1,要么填写0)。此时可用F[i][j]表示第i行状态为j时的垃圾最大值。最终的结果就是第N-M行所对应的状态中的最大值。

上一遍blog对状态压缩讲的比较详细,可以参看 http://blog.csdn.net/lu597203933/article/details/44137277

代码:

#include <iostream>
#include <memory.h>
#include <time.h>
using namespace std;
#define NMax 1000
#define MMax 1 << 10
long long F[NMax][MMax];

bool testCompatibility(int j, int M, int Q)     // 判断该状态j是否是连续的M中有大于Q个1
{
	int i = 0;
	int count = 0;
	while(i < M)
	{
		if(j & (1 << i))
		{
			count ++;
		}
		i++;
	}
	if(count > Q)return false;
	else return true;
}
long long getFirstLine(int j, int M, int *W)   //  得到“第一行”的垃圾总量
{
	int i = 0;
	long long rubbish = 0;
	while(i < M)
	{
		if(j & (1 << i))
		{
			rubbish += W[M-1-i];
		}
		i++;
	}
	return rubbish;
}

bool testRemaining(int j, int k, int M)     // 判断j的最高M-1位是否等于k的低M-1位  即判断状态j与上一状态k是否兼容
{
	k = k & ~(1<<(M-1));   // 将k的第M-1位置0
	k = k << 1;
	k = k | (j & 1);
	if (k == j) return true;
	else return false;
}

int main()
{
	int N, M, Q;
	while(cin >> N >> M >> Q){
		int W[NMax];
		int sta[NMax];
		int tt = 0;
		int allStates = 1 << M;
		int i, j;
		for(i = 0; i < N; i++)
			cin >> W[i];

		memset(F, 0 , sizeof(F));
		long long maxRubbish = 0;

		for(j = 0; j < allStates; j++)
		{
			if(testCompatibility(j, M, Q))
			{
				sta[tt++] = j;		  //  将可用的状态保存到一个数组sta中  如果没有这个sta 则需要遍历所有的状态
			}
		}

		for(int j = 0; j < tt; j++)
			F[0][j] = getFirstLine(sta[j], M, W);   // 得到前m个单元的状态

		for(i = 1; i <= N - M; i++)
		{
			for(j = 0; j < tt; j++)
			{
				for(int k = 0; k < tt; k++)
				{
					int aa = sta[k] & ~(1<<(M-1));   // 将k的第M-1位置0
					aa = aa<< 1;
					aa = aa | (sta[j] & 1);
					//if(testRemaining(sta[j], sta[k], M))       //  在循环中尽量不要用函数,否则调用开销会很大
					if(aa == sta[j])
					{
						F[i][j] = max(F[i-1][k],F[i][j]);
					}
				}
				if(((sta[j] & 1) == 1))
				{
					F[i][j] += W[i+M-1];
				}
			}
		}

		for(int j = 0; j < tt; j++)
			maxRubbish = max(maxRubbish, F[N-M][j]);
		cout << maxRubbish << endl;
	}
	return 0;
}

/*
input:
5 2 1
36 9 80 69 85

10 8 3
38 98 97 87 76 67 56 65 53 76

output:
201
362
*/

但是此题我代码提交的时候TLE,显示超时了,但是我自己将所用时间输出来了了,比网上给的代码http://hhfgeg.name/?id=158还有少,但始终TLE,不知道为什么,有知道的可以评论。谢谢!

下面总结一般状态压缩的解法步骤

1:初始化,初始化第0行各状态所对应的方案数(垃圾量)

2:通过判断第i行的状态j是否与上一行的各状态的兼容性去求F[i][j]

3:通过题目求出最终的结果

时间: 2025-01-01 12:13:44

算法练习系列—hiho1044 状态压缩二(捡垃圾)的相关文章

算法练习系列—hiho1048 状态压缩一(铺地砖)

题目地址:http://hihocoder.com/problemset/problem/1048 编程之美的课后题也有一个和整个题目一样的.(P269) 题目 这个题目的题意很容易理解,在一个N*M的格子里,我们现在有两种类型的砖块,1 * 2和 2 * 1,问一共有多少种方案,可以将整个N*M的空间都填满. 最简单的例子就是下面的了: 编程之美中题目: 某年夏天,位于希格玛大厦四层的微软亚洲研究院对办公楼的天井进行了一次大规模的装修.原来的地板铺有 N×M 块正方形瓷砖,这些瓷砖都已经破损老

hihoCoder 1048 : 状态压缩&#183;二

题目链接:http://hihocoder.com/problemset/problem/1048 题目大意:用1*2或者2*1的方块铺满一个N*M的大方格,共有多少种方法.结果对1e9+7取余.2<=N<=1000, 3<=m<=5 解题思路:挑战程序设计竞赛上有基本上一样的题目,可以参考,原题中也有提示.大致思路就是,如果从左往右铺的话,那么对第i行j列的方块来说,第i-1行的方块一定全部铺过,第j+2行的一定没有铺过.所以我们可以保存第i行和第i+1行的状态,然后递推.又由于

HihoCoder第九周 状态压缩 二 与POJ2411总结

在此我向各位博友求助,特别想知道除了HihoCoder上面的结果要对1e9+7取余之外,这两道题还有什么其他的问题,都是骨牌覆盖问题,都是状态压缩+dp,为什么我能过poj2411的程序过不了HihoCoder,还不是其他诸如TimeLimited,而是Wrong Answer,这个问题我想了很久,还是不知道是怎么回事,如果有神通广大的博友知道答案,希望你能告诉我.顺便说一下,HihoCoder给的那个hint只看懂了一部分递推的公式,其中满足的那个条件还是不懂. 两个题目的连接地址: http

hihoCoder #1044 : 状态压缩&#183;一 (清垃圾)

题意: 某车厢有一列座位,共有n个位置,清洁工要在这n个位置上清垃圾,但是不能全部位置都清理,只能选择部分.选择的规则是,连续的m个位置内,不能够清理超过q个,也就是说从第1~m个位置最多可以清q个,清q+1个就不行了.当然,q一般是小于m的,不然岂不是可以m个位置全清了?那就没限制了. 思路:看小hi小ho讲的完全是一知半解,看了大神的代码一整天才看懂意思.下面做分析(以我能理解的角度,以及通俗的角度,方便回忆.): 三个变量的定义: n: 一共有n个座位. m: 在m个连续的座位. q:最多

HDU 4539 郑厂长系列故事——排兵布阵 (状态压缩DP)

中文题,题意不再累赘. 思路:对于第 i 行的放士兵,影响它的只有第 i-1 行和 i-2 行,所以暴力枚举符合这三行的状态 state[i],state[j],state[k].  接下来就是二进制的巧妙应用了. 具体题解看代码注释!!! #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #include<cmath&

奇妙的算法—状态压缩动态规划

华电北风吹 天津大学认知计算与应用重点实验室 日期:2015/8/27 由于代码未调试完全正确论文草稿呈现 poj上一道需要用到状态压缩动态规划,链接http://poj.org/problem?id=3254 网上看到有很多人写出了代码,参考了一个带备忘的自顶向下的动态规划解法,自己写了一个有底向上的动态规划解法 有底向上: #include<iostream> #include<math.h> #include<ostream> #include<fstrea

【算法学习笔记】62.状态压缩 DP SJTU OJ 1088 邮递员小F

状态压缩,当我们的状态太多时可以考虑用bit来存储,用二进制来表示集合,用&来取交集,用^来异或. DP过程很简单,遍历所有情况取最短路径就行,因为最短哈密顿回路本身就是一个NPC问题,效率不高. #include <vector> #include <iostream> using namespace std; //最短哈密顿回路问题 NP完全问题... int map[16][16]={0}; int n=0; const int INF=768000;//3000*1

ACM: HDU 5418 Victor and World - Floyd算法+dp状态压缩

HDU 5418 Victor and World Time Limit:2000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u After trying hard for many years, Victor has finally received a pilot license. To have a celebration, he intends to buy himself an airplane and fl

hiho #1044 : 状态压缩&#183;一

描述 小Hi和小Ho在兑换到了喜欢的奖品之后,便继续起了他们的美国之行,思来想去,他们决定乘坐火车前往下一座城市——那座城市即将举行美食节! 但是不幸的是,小Hi和小Ho并没有能够买到很好的火车票——他们只能够乘坐最为破旧的火车进行他们的旅程. 不仅如此,因为美食节的吸引,许多人纷纷踏上了和小Hi小Ho一样的旅程,于是有相当多的人遭遇到了和小Hi小Ho一样的情况——这导致这辆车上的人非常非常的多,以至于都没有足够的位置能让每一个人都有地方坐下来. 小Hi和小Ho本着礼让他们的心情——当然还因为本