Class & Homework - BFS

Catch That Cow // poj 3278

一个样例程序,速度一般,但思路清晰

#include <iostream> 
#include <cstring> 
#include <queue>
using namespace std;
const int MAXN=100000;
int visited[MAXN+2]; //访问过的地址
struct Step{
	int x; //坐标
	int s; //已经走了多少步
	Step(int x_,int s_):x(x_),s(s_){} 
}; 
queue<Step> q;

int main(){
	int N,K; 
	scanf("%d %d",&N,&K);
	memset(visited,0,sizeof(visited));
	q.push(Step(N,0)); visited[N]=1; //初始化 
	while(!q.empty()){
		Step t=q.front();
		if(t.x==K){
			printf("%d\n",t.s);
			break;
		}
		else{
			if(t.x-1>=0&&!visited[t.x-1]){
				q.push(Step(t.x-1,t.s+1));
				visited[t.x-1]=1;
			}
			if(t.x+1<=MAXN&&!visited[t.x+1]){
				q.push(Step(t.x+1,t.s+1));
				visited[t.x+1]=1;
			}
			if(2*t.x<=MAXN&&!visited[2*t.x]){
				q.push(Step(2*t.x,t.s+1));
				visited[2*t.x]=1;
			}
			q.pop();
		}
	}
	return 0;
}


EIGHT // poj 1077,八数码问题

郭老师给的例程,最简单做法,poj  437ms,但在HDOJ上会TLE

#include <iostream>
#include <bitset>
#include <cstring>
using namespace std;
int goalStatus; //目标状态
bitset<362880> Flags; //节点是否扩展的标记
const int MAXS = 400000; //>400000
char result[MAXS]; //结果
struct Node {
	int status; //状态, 即排列的编号
	int father; //父节点指针
	char move; //父节点到本节点的移动方式u/d/r/l
	Node(int s, int f, char m):status(s), father(f), move(m) { }
	Node() { }
};
Node myQueue[MAXS]; //状态队列, 状态总数362880
int qHead;
int qTail;
//队头指针和队尾指针
char sz4Moves[] = "udrl"; //四种动作
unsigned int factorial[21];
//存放0-20的阶乘. 21的阶乘unsigned放不下了

//给定排列, 求序号
unsigned int GetPermutationNumForInt(int * perInt, int len){
//perInt里放着整数0到(len-1)的一个排列, 求它是第几个排列
//len不能超过21
	unsigned int num = 0;
	bool used[21];
	memset(used, 0, sizeof(bool)*len);
	for( int i = 0; i < len; ++ i ) {
		unsigned int n = 0;
		for( int j = 0; j < perInt[i]; ++ j) {
			if( !used[j] ) ++n;
		}
		num += n * factorial[len-i-1];
		used[perInt[i]] = true;
	}
	return num;
}

//给定排列,求序号
template< class T>
unsigned int GetPermutationNum( T s1, T s2, int len ){
//[s1,s1+len)里面放着第0号排列,[s2,s2+len)是要求序号的排列
//两者必须一样长, len不能超过21
//排列的每个元素都不一样. 返回排列的编号
	int perInt[21]; //要转换成[0, len-1] 的整数的排列
	for( int i = 0; i < len; ++i )
	for( int j = 0; j < len; ++j ) {
		if( * ( s2 + i ) == * ( s1 + j )) {
			perInt[i] = j;
			break;
		}
	}
	unsigned int num = GetPermutationNumForInt(perInt, len);
	return num;
}

template <class T>
void GenPermutationByNum(T s1, T s2, int len, unsigned int No)
//根据排列编号,生成排列
{ //[s1,s1+len) 里面放着第0号permutation,排列的每个元素都不一样
	int perInt[21]; //要转换成[0,len-1] 的整数的排列
	bool used[21];
	memset(used, 0, sizeof(bool)*len);
	for(int i = 0; i < len; ++ i ) {
		int j;
		for( j = 0; j < len; ++j ) {
			if( !used[j] ) {
				if( factorial[len - i - 1] >= No+1) break;
				else No -= factorial[len - i - 1];
			}
		}
		perInt[i] = j;
		used[j] = true;
	}
	for( int i = 0;i < len; ++i )
		* ( s2 + i ) = * ( s1 + perInt[i]);
}

//字符串形式的状态, 转换为整数形式的状态(排列序号)
int StrStatusToIntStatus( const char * strStatus){
	return GetPermutationNum( "012345678", strStatus, 9);
}
//整数形式的状态(排列序号), 转换为字符串形式的状态
void IntStatusToStrStatus( int n, char * strStatus){
	GenPermutationByNum((char*)"012345678", strStatus, 9, n);
}

int NewStatus( int nStatus, char cMove) {
//求从nStatus经过cMove 移动后得到的新状态. 若移动不可行则返回-1
	char szTmp[20]; int nZeroPos;
	IntStatusToStrStatus(nStatus, szTmp);
	for( int i = 0;i < 9; ++ i )
		if( szTmp[i] == '0' ) {
			nZeroPos = i;
			break;
		} //返回空格的位置
	switch( cMove) {
		case 'u': if( nZeroPos - 3 < 0 ) return -1; //空格在第一行
				else { szTmp[nZeroPos] = szTmp[nZeroPos - 3];
				szTmp[nZeroPos - 3] = '0'; }
				break;
		case 'd': if( nZeroPos + 3 > 8 ) return -1; //空格在第三行
				else { szTmp[nZeroPos] = szTmp[nZeroPos + 3];
				szTmp[nZeroPos + 3] = '0'; }
				break;
		case 'l': if( nZeroPos % 3 == 0) return -1;
		//空格在第一列
				else { szTmp[nZeroPos] = szTmp[nZeroPos -1];
				szTmp[nZeroPos -1 ] = '0'; }
				break;
		case 'r': if( nZeroPos % 3 == 2) return -1;
		//空格在第三列
				else { szTmp[nZeroPos] = szTmp[nZeroPos + 1];
				szTmp[nZeroPos + 1 ] = '0'; }
				break;
	}
	return StrStatusToIntStatus(szTmp);
}

bool Bfs(int nStatus) { //寻找从初始状态nStatus到目标的路径
	int nNewStatus; Flags.reset(); //清除所有扩展标记
	qHead = 0; qTail = 1;
	myQueue[qHead] = Node(nStatus, -1, 0);
	while ( qHead != qTail) { //队列不为空
		nStatus = myQueue[qHead].status;
		if( nStatus == goalStatus ) //找到目标状态
		return true;
		for( int i = 0;i < 4;i ++ ) { //尝试4种移动
			nNewStatus = NewStatus(nStatus, sz4Moves[i]);
			if( nNewStatus == -1 ) continue; //不可移, 试下一种
			if( Flags[nNewStatus]) continue; //扩展标记已经存在, 则不入队
			Flags.set(nNewStatus, true); //设上已扩展标记
			myQueue[qTail++] = Node(nNewStatus, qHead, sz4Moves[i]);
			//新节点入队列
		}
		qHead ++;
	}
	return false;
}

int main(){
	factorial[0] = factorial[1] =1;
	for(int i = 2;i < 21; ++i )
	factorial[i] = i * factorial[i-1];
	goalStatus = StrStatusToIntStatus("123456780");
	char szLine[50];
	char szLine2[20];
	while( cin.getline(szLine, 48)) {
		int i, j;
		//将输入的原始字符串变为数字字符串
		for( i = 0, j = 0; szLine[i]; i ++ ) {
			if( szLine[i] != ' ' ) {
				if( szLine[i] == 'x' ) szLine2[j++] = '0';
				else szLine2[j++] = szLine[i];
			}
		}
		szLine2[j] = 0; //字符串形式的初始状态
		int sumGoal = 0; //从此往后用奇偶性判断是否有解
		for( int i = 0; i < 8; ++i )
		sumGoal += i-1;
		int sumOri = 0;
		for( int i = 0; i < 9; ++i ) {
			if( szLine2[i] == '0')
			continue;
			for( int j = 0; j < i; ++j ) {
				if( szLine2[j] < szLine2[i] && szLine2[j] != '0' )
				sumOri ++;
			}
		}
		if( sumOri %2 != sumGoal %2 ) {
			cout << "unsolvable" << endl;
			continue;
		}
		//上面用奇偶性判断是否有解
		if( Bfs(StrStatusToIntStatus(szLine2))) {
			int nMoves = 0;
			int nPos = qHead;
			do { //通过father找到成功的状态序列, 输出相应步骤
				result[nMoves++] = myQueue[nPos].move;
				nPos = myQueue[nPos].father;
			} while( nPos ); //nPos = 0 说明已经回退到初始状态了
			for( int i = nMoves -1; i >= 0; i -- )
			cout << result[i];
		}
		else
		cout << "unsolvable" << endl;
	}
}


Flip Game // oj 1753

第一次写还是遇上了一点挑战,主要是怎样存储数据。棋盘的结构相当好,16个格子,用 short 刚好能表示。

所以,改用位运算后,哪怕不剪枝都能过。

#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
bool board[4][4];
struct Board{
	short b;
	short visited;
	short step;
	Board():b(0),visited(0),step(0){
		for(int i=0;i<4;++i) for(int j=0;j<4;++j) b^=board[i][j]<<(15-4*i-j);
	}
};
void flip(int i,int j,Board&p){
	p.b^=1<<(15-4*i-j);
	if(i>0) p.b^=1<<(19-4*i-j);
	if(j>0) p.b^=1<<(16-4*i-j);
	if(i<3) p.b^=1<<(11-4*i-j);
	if(j<3) p.b^=1<<(14-4*i-j);
}
bool check(const Board&p){
	return p.b==0 || p.b==short(~0);
}
queue<Board> q;

int main(){
	for(int i=0;i<4;++i) for(int j=0;j<4;++j){
		char c; scanf("%c",&c);
		board[i][j]= (c=='b')?1:0;
		if(j==3) scanf("%c",&c);
		q.push(Board());
	while(!q.empty()){
		Board t=q.front();
		if(check(t)){
			printf("%d\n",t.step); 
			return 0;
		}
		for(int i=0;i<4;++i) for(int j=0;j<4;++j){
			if(!((t.visited>>(15-4*i-j))&&1)){
				Board tt=t;
				tt.visited^=1<<(15-4*i-j);
				flip(i,j,tt);
				++tt.step;
				q.push(tt);
			}
		}
		q.pop();
	}
	printf("Impossible\n");
}

迷宫问题 // oj 4127

算是第一次自己写路径记忆,需要明确,last 最好是 node*,因为如果记录它在store中的位置,同一节点不同路径就不好说了。另外的问题在于,既然使用指针,这些结点都要存起来,那么 last 应对应它在 store 中的位置。

【待优化】

#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
bool maze[5][5];
bool visited[5][5];
struct node{
	int i,j;
	int pos; //在store中的位置
	node*last;
	node(){}
	node(int i_,int j_,int p,node*l):i(i_),j(j_),pos(p),last(l){} 
}store[101];
int pos=0;
queue<node> q;

int main(){
	for(int i=0;i<5;++i) for(int j=0;j<5;++j) scanf("%d",maze[i]+j);
	node t(0,0,0,NULL);
	visited[0][0]=1;
	q.push(t); store[pos++]=t;
	while(!q.empty()){
		node t=q.front();
		int p=t.pos;
		if(t.i==4&&t.j==4){
			vector<node*> out;
			node *l = &t;
			int cnt=0;
			while(l!=NULL){
				out.push_back(l);
				++cnt;
				l=l->last;
			}
			for(int k=cnt-1;k>=0;--k) printf("(%d, %d)\n",out[k]->i,out[k]->j);
			return 0;
		}
		if(t.i<4&&maze[t.i+1][t.j]==0&&!visited[t.i+1][t.j]){
			q.push(node(t.i+1,t.j,pos,store+p));
			store[pos++]=node(t.i+1,t.j,pos,store+p);
			visited[t.i+1][t.j]=1;
		}
		if(t.j<4&&maze[t.i][t.j+1]==0&&!visited[t.i][t.j+1]){
			q.push(node(t.i,t.j+1,pos,store+p));
			store[pos++]=node(t.i,t.j+1,pos,store+p);
			visited[t.i][t.j+1]=1;
		}
		q.pop();
	}
}

以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值