洛谷 P3930 SAC E#1 - 一道大水题 Knight

博客讲述了在解决洛谷P3930题目时遇到的大内存问题,通过优化状态记录,将原本的f数组用bool存储状态并结合queue中的dis值,成功降低了内存消耗。博主分享了代码优化过程和避免queue炸内存的技巧,并建议这类题目可作为练习编程速度和能力的选择。
摘要由CSDN通过智能技术生成
这题,又是一道卡内存的shabby题。
一眼看,广搜,加个状态记录哪些黑子已经被消灭了,十分套路。f[x][y][p]表示,走到(x,y),黑子被消灭的状态是p的最小步数。可是, 50*50 *1<<16 ,这个数组,貌似500MB也不太够,现在就来优化一下这个内存吧。
由于每次的步数增加都是1,所以,在广搜中,可以保证,队列前面的值小于等于队列后面的值,所以,对于一个[x][y][p](意思就是:现在的位置,消灭的黑子)的状态来说,当它出现第一次的时候,它的步数值,一定已经是最优的了,后面是不会更新到比它此刻的值还要优的值了的,所以,对于f[x][y][p]来说,不会出现第二次f[x][y][p]>f[nowx][nowy][nowp]+1的情况了,所以,f数组只会更新一次,那么就可以用bool来存储是否更新过了,然后在queue中,新增加一个dis值,就可以了。比原来的int小4倍内存。
现在可能有人会问,那queue里面增加了一个dis值会不会导致炸内存呢?我有个同学就说他queue炸内存了。其实是因为他写挂了,状态冗余导致的。每次取出一个值,然后再放进去最多8个值(而这8个值,可能远远不会到),是基本不会是的queue炸内存的。这样,就把f数组成功给优化了。
除了内存这个坑点加麻烦点意外,别的就是纯码量了,我的代码写的比较傻,会有一个比较大的常数,因为有很多无用判断都可以省略,但我没省略。但是,还是跑的挺快的。
没省略的原因有二:1.全部写上不用动脑子想哪些需要省略哪些不需要省略,提供正确率,节省时间;2.使得代码比较对称,长的代码,如果对称了,就有层次感,无论是自己检查起来还是别人看起来都更加方便。
#include <bits/stdc++.h>
using namespace std;
const int dx[8]={
   -1,-2,-2,-1,1,2,2,1},dy[8]={
   -2,-1,1,2,-2,-1,1,2};
const int N=60;
int n,cnt,sx,sy,tx,ty,max_statue;
int mp[N][N];
bool f[N][N][1<<16];
char str[N][N];
struct number{
   int x,y; char id;}num[N*N];
struct node{
   int x,y,p,dis;};

inline bool pd(int x,int y,int p)
{
   
	int x1,y1;
	if (x<1 || x>n || y<1 || y>n) return false;
	int xx,yy;
	char id;
	for (register int i=1; i<=cnt; ++i)
	if (!((1<<(i-1))&p))
	{
   
		xx=num[i].x; yy=num[i].y; id=num[i].id;
		if (xx==x && yy==y) continue; //如果把这个棋子吃了,就OK了 
		
		if (id=='C')   //有阻挡 
		{
   
			x1=xx; y1=yy;
			while (x1-1>=1)
			{
   
				x1--;
				if (mp[x1][y1])
				{
   
					if (!((1<<(mp[x1][y1]-1))&p)) break;
				}
				if (x1==x && y1==y) return false;	
			}
			x1=xx; y1=yy;
			while (x1+1<=n)
			{
   
				x1++;
				if (mp[x1][y1])
				{
   
					if (!((1<<(mp[x1][y1]-1))&p)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值