状态压缩初探(包含蓝桥算法训练 和为T,牛客 csl的校园卡)

在做题的时候,内存总是限制着我们.如果有一些数据的状态需要你标记或者记录,数据很小都好解决,直接记录就行,但是如果数据过大,内存就会超限,又如何解决呢?这个时候就可以采用状态压缩.

状态压缩并不是指某种算法,它是指一种思想,将很大的空间进行一种压缩,但是又可以保证原本需要记录的东西被记录下来的思想,现实生活中的二维码在我看来就是一种状态压缩,将信息都压缩在一张黑白格子图上,在二维码被扫描的时候进行解码复原,就会获得原本要储存的信息,大大节省了储存空间.在各种状态压缩的方式中,个人感觉二进制压缩法是最为省空间和便捷的.在下面先讲一下蓝桥算法训练的和为T,了解二进制压缩法是怎样把状态进行压缩的.


题目连接:http://lx.lanqiao.cn/problem.page?gpid=T290

试题 算法训练 和为T

问题描述

  从一个大小为n的整数集中选取一些元素,使得它们的和等于给定的值T。每个元素限选一次,不能一个都不选。

输入格式

  第一行一个正整数n,表示整数集内元素的个数。
  第二行n个整数,用空格隔开。
  第三行一个整数T,表示要达到的和。

输出格式

  输出有若干行,每行输出一组解,即所选取的数字,按照输入中的顺序排列。
  若有多组解,优先输出不包含第n个整数的;若都包含或都不包含,优先输出不包含第n-1个整数的,依次类推。
  最后一行输出总方案数。

样例输入

5
-7 -3 -2 5 9
0

样例输出

-3 -2 5
-7 -2 9
2


这个题一开始我是用dfs做的,简单的拼数问题,dfs模板,但是我忽略了输出顺序,导致只得了80分.后来采用了二进制压缩的方法,把每种取数的情况列举才ac.先上代码,在详细讲解思路:

#include<iostream>
#include<cmath>
using namespace std;
int a[23],vis[23],summ=0;
void print(int idx){
	for(int i=0;i<idx;i++)cout<<vis[i]<<" ";
	cout<<endl;
	summ++;
	return;
}
int main(){
	int n,m,t;
	cin>>n;
	for(int i=0;i<n;i++)cin>>a[i];
	cin>>m;
	for(int i=1;i<pow(2,n);i++){
		t=i;
		int idx=0,sum=0,mm=0;
		while(mm!=n){
			if(t%2==1){
				vis[idx]=a[mm];
				idx++;
				sum+=a[mm];
			}
			t/=2;
			mm++;
		}
		if(sum==m)print(idx);
	}
	cout<<summ;
}

二进制压缩:

就拿样例讲,一共有五种数字,我们可以拿一个五位的二进制数来表示他们的拿取状态,1表示当前位子已经取过,0表示没被拿.从右往走,分别是1,2,3,4....什么都不拿的情况就是00000,拿第一个就是00001,拿第五个和第三个就是10100,拿第二个第四个就可以记录为01010.这样就用了一个五位二进制数,最大是63,记录下了所有的63种情况.再用一个for循环从1循环到63,将每种情况列举进行计算,如果满足条件就输出.而且因为是从00001开始,刚好满足题目中的输出条件.这就是二进制压缩的思想,有了思想就可以看下一个题了.


链接:https://ac.nowcoder.com/acm/contest/16910/D
来源:牛客网
 

题目描述

今天是阳光明媚,晴空万里的一天,CSL早早就高兴地起床走出寝室到校园里转悠。

但是,等到他回来的时候,发现他的校园卡不见了,于是他需要走遍校园寻找它的校园卡。CSL想要尽快地找回他掉的校园卡,于是便求助于OneDay帮他一起找。

OneDay和CSL在同一已知的地点出发,并以相同的速度(1格/秒)搜索校园,试求两人走遍校园的最短时间。

输入描述:

第一行为两个整数n,m(1 ≤ n, m ≤ 4),表示地图的大小。接下来是n行m列的地图:X表示障碍物,S表示起点,O表示空地。障碍物不能直接经过,数据保证所有空地是可达的,起点有且只有一个。

输出描述:

输出一个整数表示两人共同走遍校园所需的最少时间。

示例1

输入

3 4
XSOO
OOXO
OOOO

输出

5  5

说明

 

输入

2 3
XSX
OOO

输出

2

输入

4 4
SOOO
OOOO
OOOO
OOOO

输出

8

看见这个题第一眼就会想到bfs,但是细看又好像不是,该如何记录他们走的状态呢?两个人走重复的路又怎么标记呢?这个时候再去回过头看看之前的状态压缩:

我们可以把地图变为一个二进制数来进行储存:

当地图为

OOSO

XXOO

OOOO

时我们把当前状态进行储存,记录为

0010

1100

0000

有感觉了吗?那么两人分别往左往下走一步走一步就可以记录为:

0110

1110

0000

这样就把每种状态记录了,记录了每种状态,就可以防止重复了!但是要注意,还要同步记录此时两人的位置,防止重复.当你把这个状态记录后,那它就变成了一个bfs问题了(bfs在我的博客中详细见:https://mp-new.csdn.net/mp_blog/creation/editor/116354137),定义四个方向去搜索,遍历图直到到达一种状态,两人都走满,也就是1111 1111 1111的状态.

针对这个题还有一个问题,如何判断下一步可以不可以走呢?我们可以保留原来的地图数组,如果bfs下一步原来是'O'或者'S'就可以走,'X'就不可以走.

状态压缩重在将状态压缩后进行空间的节省,方法不止二进制一种,只要能将每种情况用一个数字或者别的什么保存,进行空间压缩,就可以称之为状态压缩.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值