洛谷P5507 双向bfs

传送门:P5507
对于大佬们来说,这题是裸的双向bfs题,但对于本蒟蒻来说,这是一道裸的 WA自动机(手动滑稽
当然,本蒟蒻也会看题解的,知道这是双向BFS之后,就决定尝试上代码,结果:双向BFS双倍爽

我是不会告诉你们我调代码调了一晚上的
先上AC代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=(1<<25);
int f1[20],f2[20],f3[20],f4[20];
int vis[MAXN],fa[MAXN],fw[MAXN];
int choice[MAXN];
int ans1[MAXN],ans2[MAXN];
int state;
int m1,m2,mid; 
bool flag=0;
int findstate(int t,int len)
{return (t>>((len-1)<<1))&3;}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	for(int i=1;i<=12;i++)
	{
		int now;
		cin>>now>>f1[i]>>f2[i]>>f3[i]>>f4[i];
		now--;
		state=state^(now<<((i-1)<<1));
	}
//	cout<<(bitset<24>)state<<endl;
	queue<int >q;
	q.push(state);//初始状态压入 
	q.push(0);//最终态压入 
	fw[state]=1;fw[0]=-1;//1 表示正向  -1表示逆向 
	vis[state]=1;vis[0]=1;// 标记是否走过 
	while(!q.empty()&&flag==0)
	{
		int t=q.front();q.pop();// t 表示队首 
		for(int i=1;i<=12;i++)// 枚举所有可能发生变化的钮扣 
		{	
			int nnstate,nstate,nextstate;
			int gai;// gai表示会发生连锁的纽扣号码 
			nstate=findstate(t,i);// findstate 用于找第 i 个纽的状态
			//cout<<(bitset<24>)t<<endl;
			//cout<<(bitset<2>)nstate<<endl;  
			if(fw[t]==1)// 如果是正向 
			{
				if(nstate==0)gai=f1[i];
			    else if(nstate==1)gai=f2[i];
			    else if(nstate==2)gai=f3[i];
			    else if(nstate==3)gai=f4[i];
			//	cout<<(bitset<24>)t<<endl;
			//	cout<<(bitset<2>)nstate<<endl;
			//	cout<<(bitset<24>)(((nstate+1)&3)<<((i-1)<<1))<<endl;
				nextstate=(t^(nstate<<((i-1)<<1)))^(((nstate+1)&3)<<((i-1)<<1));//首先转动第 i 个纽扣 nextstate表示转动后的状态 这里注意(nstate+1)&3要用括号包住 
			//	cout<<i<<' '<<(bitset<24>)nextstate<<endl;
				nnstate=findstate(nextstate,gai);
			//	cout<<gai<<' '<<(bitset<2>)nnstate<<endl;
			//    cout<<(bitset<24>)(nextstate^(nnstate<<((gai-1)<<1)))<<endl;
				nextstate=nextstate^(nnstate<<((gai-1)<<1))^(((nnstate+1)&3)<<((gai-1)<<1));// 现在的next表示发生连锁之后的状态 
			//	cout<<(bitset<24>)nextstate<<endl;
			}
			else//如果当前状态是反向的,就要回溯到前一步 
			{
				nextstate=t^(nstate<<((i-1)<<1))^(((nstate+3)&3)<<((i-1)<<1));//nextstate 表示转动到t之前的状态
				nstate=findstate(nextstate,i);
				if(nstate==0)gai=f1[i];
			    else if(nstate==1)gai=f2[i];
			    else if(nstate==2)gai=f3[i];
			    else if(nstate==3)gai=f4[i];
			    nnstate=findstate(nextstate,gai);
			    nextstate=nextstate^(nnstate<<((gai-1)<<1))^(((nnstate+3)&3)<<((gai-1)<<1));
			} 
		//	cout<<(bitset<24>)nextstate<<endl;
			if(vis[nextstate]==1) 
			{
				if(fw[nextstate]==fw[t])continue;
				else 
				{
					m1=fw[t]==1?t:nextstate;
					mid=i;
					m2=fw[t]==1?nextstate:t;	
					flag=1;break;
				}
			}
			vis[nextstate] = 1;
            fw[nextstate] = fw[t]; //继承方向
            fa[nextstate] = t;          //用于回溯操作
            choice[nextstate] = i ;   //记录本次操作
            q.push(nextstate);
		}
	}
	//cout<<(bitset<24>)m1<<endl;
	//cout<<(bitset<24>)m2<<endl;
	int cnt1 = 0,st = m1,cnt2 = 0;
    while(st!= state){
        ans1[++cnt1] = choice[st];
        st = fa[st];
    }
    //逆向回溯
    st= m2;
    while(st != 0)
	{
        ans2[++cnt2] = choice[st];
        st= fa[st];
    }
    cout<<cnt1+cnt2+1<<endl;
    for(int i = cnt1; i; i--) cout<<ans1[i]<<' ';
    cout<<mid<<' ';
    for(int i=1;i<=cnt2;i++) cout<<ans2[i]<<' ';
	return 0;
 } 

这题的变量可以说多到令人疯狂,所以在写代码的时候还要一边给自己加注释。注释的部分是调代码的过程,还有好多删掉了,代码里保留的是最后一次调试的过程。


先聊聊双向BFS的思路吧。
这道题如果暴力来解就是BFS,把每一种可能的情况压入队列中,当出现终态的时候输出就行,但是明眼人都看的出来,暴力出不了奇迹,时间复杂度直接爆炸。
那么思路是BFS,怎么加速呢?一个不行那就来两个,双向BFS永远的神!
双向BFS适用于已知初态和终态的情况,从两段出发,相遇时就是答案。

思路极其简单,代码写的人飘起来。


再补充一个知识点
将数字以二进制的形式输出的方式为:cout<<(bitset<24>)t<<endl;
中间的24是输出24位,可以自由选择输出多少位。
这个方式在位运算参与的算法中可以起调试作用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值