2021 沈阳站 Luggage Lock(最小操作次数 转化为 最短路)

题目链接


题意:

对于一个长度为4的数字字符串,每次操作可以使得连续若干位置上的数都+1或者-1。(符号9加1变为0,符号0减1变为9)
给定两个字符串a,b。问,字符串a转化为字符串b所需要的最少操作次数。
最多1e5次询问。

思路:

对于一种字符串,其可以转化成的状态一共有4+3+2+1=10种。一共最多有 1 0 4 10^4 104种状态。
所以可以将一种状态看作一点,可以相互转化的状态之间连边,权值为1,建图。
问,从一种状态到另一种状态的最少操作数 ,也就转化为求两点之间的最短距离。

但是一共有1e5次询问,如果每次询问都bfs一遍的话,超时。
如何优化呢?

考虑若初始状态为2222、目标状态为3333,这种询问的操作数和初始状态为0000、目标状态为1111的操作数是相同的。
那么我们就可以都将从初始状态转化为目标状态所相差的状态表示出(也就是将两个状态搞一个偏移量,初始状态偏移到0000,重新表示目标状态),只需要求出0000状态到该状态所需要的操作数就可。
这样,只需要求从0000状态开始,到所有状态的最短路径即可,只需要一次bfs。

对于每次询问,直接输出即可。

Code:

map<string,int> mp;

const int N = 200010, mod = 1e9+7;
int T, n, m;
string a,b;
string dir[30]={"1000","0100","0010","0001","1100","0110","0011","1110","0111","1111","2000","0200","0020","0002","2200","0220","0022","2220","0222","2222"};

void bfs()
{
	mp.clear();
	mp["0000"]=0;
	queue<string> que;
	que.push("0000");
	
	while(que.size())
	{
		string y=que.front();que.pop();
		for(int i=0;i<20;i++)
		{
			string x=y,d=dir[i];
			for(int j=0;j<4;j++)
			{
				if(d[j]=='1') x[j]=(x[j]-'0'+1+10)%10+'0';
				else if(d[j]=='2') x[j]=(x[j]-'0'-1+10)%10+'0';
			}
			if(!mp.count(x)){
				mp[x]=mp[y]+1;
				que.push(x);
				if(x==a) return;
			}
		}
	}
}

int main(){
	Ios;
	cin>>T;
	
	bfs();
	while(T--)
	{
		cin>>a>>b;
		for(int i=0;i<4;i++){
			a[i] = (a[i]-b[i]+10)%10+'0';
		}
		cout<<mp[a]<<"\n";
	}
	return 0;
}

经验:

之前也做过一个这样 字符串转化最小次数问题 转化为 最短路问题,AtCoder 224.D - 8 Puzzle on Graph 但是看到这题还是没想起来。。
还有一个重要的思维转化,将初始和目标状态搞个偏移量,妙!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值