题意:
给出一个四位数字字符串,可以对其中任意长度的区间同时+1或-1,其中9+1会变成0,0-1会变成9,并且给出四位目标字符串,求变成目标字符串的最小操作次数
Solution:
没有想法就搜索,就4位,爆搜都是接近O(1)O(1)O(1)的复杂度,不妨将四位分成若干组,然后对每组求最小次数,然后合并答案,取最优答案。有如下这么多分组
vector<vector<int>>vv={
{1,1,1,1},
{1,1,2},
{1,2,1},
{1,3},
{2,1,1},
{2,2},
{3,1},
{4}
};
对每一组,要么同时+1,要么同时-1才是最快的,这样的操作就转化成了经典例题(洛谷P5019),只需要求+1的次数和-1的次数取最小即可,需要注意的是,如果某一位已经和目标字符一样了,它可以有两种情况的操作次数{0,10}\{0,10\}{0,10},而非{0,0}\{0,0\}{0,0}
// #include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
using ll=long long;
const int N=100005,inf=0x3fffffff;
const long long INF=0x3f3f3f3f3f3f,mod=998244353;
bool vis[20];
vector<vector<int>>vv={
{1,1,1,1},
{1,1,2},
{1,2,1},
{1,3},
{2,1,1},
{2,2},
{3,1},
{4}
};
char s[20],t[20];
int add[20],del[20];
int solve(int l,int r)
{
int ret=inf;
for(int i=l;i<=r;i++)
{
if(t[i]<=s[i]) add[i]=t[i]+10-s[i];
else add[i]=t[i]-s[i];
if(t[i]>=s[i]) del[i]=s[i]+10-t[i];
else del[i]=s[i]-t[i];
}
int tot1=0,tot2=0;
add[r+1]=del[r+1]=0;
for(int i=r;i>=l;i--)
{
if(s[i]==t[i])
{
if((add[i]>add[i+1])*(add[i]-add[i+1])+(add[i-1]>add[i]&&i>l)*(add[i-1]-add[i])>(0>add[i+1])*(0-add[i+1])+(add[i-1]>0&&i>l)*(add[i-1]-0)) add[i]=0;
if((del[i]>del[i+1])*(del[i]-del[i+1])+(del[i-1]>del[i]&&i>l)*(del[i-1]-del[i])>(0>del[i+1])*(0-del[i+1])+(del[i-1]>0&&i>l)*(del[i-1]-0)) del[i]=0;
}
tot1+=(add[i]>add[i+1])*(add[i]-add[i+1]);
tot2+=(del[i]>del[i+1])*(del[i]-del[i+1]);
}
return min(tot1,tot2);
}
void work()
{
scanf("%s%s",s+1,t+1);
int ans=inf;
for(auto& sub:vv)
{
int done=0,tot=0;
for(auto& i:sub)
{
tot+=solve(done+1,done+i);
done+=i;
}
ans=min(ans,tot);
}
printf("%d\n",ans);
}
int main()
{
int t; cin>>t;
while(t--) work();
return 0;
}