题目链接
题意:
对于一个长度为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 但是看到这题还是没想起来。。
还有一个重要的思维转化,将初始和目标状态搞个偏移量,妙!