病毒Virus

病毒Virus

一本通P1396 病毒Virus

题目简述

给定\(k\)个被病毒感染了的字符串,知道这\(k\)个字符串原本是按字典序从小到大排列,最后给出一个待复原的字符串\(s\),要求根据上面的\(k\)个被感染的字符串复原\(s\)

  • 数据范围

\(k≤50000\)


所需算法

拓扑排序&模拟

前置知识

如果想了解拓扑排序欢迎来踩我的另一篇博客呀qvq


解题思路

感觉有点没读懂或者没思路?

那我们通过思考几个问题来找出思路:

  • \(k\)个被感染的字符串能为我们带来什么?

因为这\(k\)个字符串原本是按字典序排列的,所以是有序的;被病毒感染只会改变原来字符串的样子,但并不会影响原来的排序!

所以我们可以根据这\(k\)个字符串得出原字符\(x\)和感染后的字符\(y\)之间的对应关系!(可以理解为一一对应的映射关系)

  • 怎么找到这种映射关系?

这里我想到的做法是:双层循环+逐位查询+拓扑排序

说白点就是先模拟字典序排序的过程:如果两个字符串的第\(i\)位相等,则判断第\(i+1\)位,直到其中一个字符串完结

在这个过程中我们找到一个两个字符不同的位置,就进行连边和入度累加的操作,之后使用拓扑排序便能得到映射关系

  • 怎么想到的拓扑排序?

为了方便理解,我们插入理解一下样例:

  1. 先通过模拟字典序排序过程,我们可以得到如下的字符大小序列:\(c<e<d<a<b\)\(e<a\)

  2. 那么映射关系即:\(c->a,e->b,d->c,a->d,b->e\)(注意箭头前的是被感染后的字符,箭头后的是原始字符)

找到了一个感觉没有?qwq

\(c<e<d<a<b\)这个即是拓扑序列!然后根据这个拓扑序列我们就能够找到映射关系!


代码Code

思路就是如上这么多了,理解后应该就能A掉这道题了,只是敲代码需要细心一点

现在先放出每个关键步骤的代码段(有注释),最后会放上完整的AC代码(无注释)

  • 模拟字典序排序
for(register int i=1;i<=n;i++) {  //循环1-n个字符串,这里的n相当于题目中的k(个人习惯啦qwq)
    for(register int j=i+1;j<=n;j++) {  //循环在i之后的字符串 
        int l=0;  //l枚举字符串的位置 
        while(l<word[i].length()&&l<word[j].length()) {  //匹配长度小于两个字符串的最小长度 
              flag[word[i][l]-'0']=1;  //标记一下出现过,后面会用 
              if(word[i][l]==word[j][l]) l++;  //相同则不管 
              else {
                   flag[word[j][l]-'0']=1;
                   in[word[j][l]-'0']++;  //不同说明i串位置字符的字典序先于j串位置字符的字典序 
                   add(word[i][l]-'0',word[j][l]-'0');  //连边+入度累加 
                   break;  //找到一位后面的就不用比较了 
              }
         }
     }
}
  • 拓扑排序
for(register char i='a';i<='z';i++) {  //如果这个字符出现过且入度为0(即字典序最先),就入队 
    if(flag[i-'0']==1&&in[i-'0']==0) q.push(i-'0'); 
}
while(!q.empty()) {
      int x=q.front();
      q.pop();
      if(ans[x]!=0) {  //这里是判断一个感染字符对应多个原始字符的错误情况 
         printf("0");
         return 0;
      }
      ans[x]=sum;  //注意ans是一个整型map
      sum++;
      for(register int i=head[x];i;i=e[i].net) {  //遍历所有字典序在x之后的字符 
          int v=e[i].to;
          in[v]--;
          if(in[v]==0) q.push(v);
       }
}
  • 完整代码
#include <bits/stdc++.h>
using namespace std;
queue<int> q;
map<int,int> ans;
string word[50002];
int n,tot,sum=97,in[201],head[201],flag[201];

struct node {
    int to,net;
} e[50001];

inline void add(int u,int v) {
    e[++tot].to=v;
    e[tot].net=head[u];
    head[u]=tot;
}

int main() {
    scanf("%d",&n); 
    for(register int i=1;i<=n;i++) {
        cin>>word[i];
    }
    for(register int i=1;i<=n;i++) {  
        for(register int j=i+1;j<=n;j++) { 
            int l=0; 
            while(l<word[i].length()&&l<word[j].length()) { 
                flag[word[i][l]-'0']=1; 
                if(word[i][l]==word[j][l]) l++; 
                else {
                    flag[word[j][l]-'0']=1;
                    in[word[j][l]-'0']++; 
                    add(word[i][l]-'0',word[j][l]-'0'); 
                    break; 
                }
            }
        }
    }
    cin>>word[n+1];
    for(register char i='a';i<='z';i++) { 
        if(flag[i-'0']==1&&in[i-'0']==0) q.push(i-'0'); 
    }
    while(!q.empty()) {
        int x=q.front();
        q.pop();
        if(ans[x]!=0) { 
            printf("0");
            return 0;
        }
        ans[x]=sum;
        sum++;
        for(register int i=head[x];i;i=e[i].net) { 
            int v=e[i].to;
            in[v]--;
            if(in[v]==0) q.push(v);
        }
    }
    for(register int i=0;i<word[n+1].length();i++) {  //如果对应不完,那也是一种错误情况 
        if(ans[word[n+1][i]-'0']==0) {
            printf("0");
            return 0;
        }
    }
    for(register int i=0;i<word[n+1].length();i++) {
        cout<<char(ans[word[n+1][i]-'0']);
    }
    return 0;
} 

原文链接: https://www.cnblogs.com/Eleven-Qian-Shan/p/13218119.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    病毒Virus

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/361255

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午1:43
下一篇 2023年3月2日 下午1:44

相关推荐