代码源周赛[R47C]数字与字母
这个题目是一道图论题,其实一开始我没有想出来,我直接大模拟+小贪心。发现第二个样例没有过。那么这个题目是怎么跟图论扯上关系。
题目中说了,数字可以轮换,字母也可以轮换。那么我们就可以建图了,相邻的数字之间建一条边,边权为1。相邻的字母也建一条边,边权也是1。
题目中还说了,'0'到9'分别对应'a'到'z'。建10条边,每一条边权是0,这个很关键,题目中说了。
所以,建图的代码如下
for(int i=0;i<=9;i++){
edge[i].push_back({(i-1+10)%10,1});
edge[i].push_back({(i+1+10)%10,1});
}
for(int i=0;i<=25;i++){
edge[i+10].push_back({(i-1+26)%26+10,1});
edge[i+10].push_back({(i+1+26)%26+10,1});
}
for(int i=0;i<=9;i++){
edge[i].push_back({i+10,0});
edge[i+10].push_back({i,0});
}
从上面代码不难看出,'0'到'9'分别对应的就是0到9编码,'a'到'z'对应的是10到35
然后,我们对于字符串每一位,都跑一边最短路就可以了。不管你用SPFA,Bellman-ford,Dijsktra,Floyd,甚至是0-1BFS,都行
我写的是Dijstrak
代码如下
#include<bits/stdc++.h>
using namespace std;
struct node{
int y,v;
};
vector<node> edge[100];
char s[200005],t[200005];
int n,dist[100];
set<pair<int,int>> q;
int dij(int s,int t){
memset(dist,127,sizeof dist);
dist[s]=0;q.clear();
for(int i=0;i<=40;i++)
q.insert({dist[i],i});
while(q.size()){
int x=q.begin()->second;
q.erase(q.begin());
if(x==t||dist[x]>1<<30) break;
for(auto [y,v]:edge[x]){
if(dist[x]+v<dist[y]){
q.erase({dist[y],y});
dist[y]=dist[x]+v;
q.insert({dist[y],y});
}
}
}
return dist[t];
}
int main(){
cin.tie(0)->sync_with_stdio(0);
cin>>n>>s+1>>t+1;
for(int i=0;i<=9;i++){
edge[i].push_back({(i-1+10)%10,1});
edge[i].push_back({(i+1+10)%10,1});
}
for(int i=0;i<=25;i++){
edge[i+10].push_back({(i-1+26)%26+10,1});
edge[i+10].push_back({(i+1+26)%26+10,1});
}
for(int i=0;i<=9;i++){
edge[i].push_back({i+10,0});
edge[i+10].push_back({i,0});
}
int ans=0;
for(int i=1;i<=n;i++){
int s_px,t_px;
if('0'<=s[i]&&s[i]<='9') s_px=s[i]-'0';
else s_px=s[i]-'a'+10;
if('0'<=t[i]&&t[i]<='9') t_px=t[i]-'0';
else t_px=t[i]-'a'+10;
ans+=dij(s_px,t_px);
}
cout<<ans<<endl;
}
我一开始忘了dij板子怎么写了,然后抄了一下老师的,但是原封不动的抄了。把初始化q的0到40原封不动的抄成了1到n。害得我没调出来,赛时没有过。
以后这种板子一定要背熟,哪有考试的时候找板子的啊!

浙公网安备 33010602011771号