zoukankan      html  css  js  c++  java
  • [并查集两题]银河英雄传说,破译密文

    1、银河英雄传说

    题目描述

           公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展。 
          宇宙历七九九年,银河系的两大军事集*在巴米利恩星域爆发战争。泰山压顶集**宇宙舰队司令莱因哈特率领十万余艘战舰出征,气吞山河集*点名将杨威利组织麾下三万艘战舰迎敌。 
    杨威利擅长排兵布阵,巧妙运用各种战术屡次以少胜多,难免恣生骄气。在这次决战中,他将巴米利恩星域战场划分成30000列,每列依次编号为1, 2, …, 30000。之后,他把自己的战舰也依次编号为1, 2, …, 30000,让第i号战舰处于第i列(i = 1, 2, …, 30000),形成“一字长蛇阵”,诱敌深入。这是初始阵形。当进犯之敌到达时,杨威利会多次发布合并指令,将大部分战舰集中在某几列上,实施密集攻击。合并指令为M i j,含义为让第i号战舰所在的整个战舰队列,作为一个整体(头在前尾在后)接至第j号战舰所在的战舰队列的尾部。显然战舰队列是由处于同一列的一个或多个战舰组成的。合并指令的执行结果会使队列增大。 
    然而,老谋深算的莱因哈特早已在战略上取得了主动。在交战中,他可以通过庞大的情报网络随时监听杨威利的舰队调动指令。 
          在杨威利发布指令调动舰队的同时,莱因哈特为了及时了解当前杨威利的战舰分布情况,也会发出一些询问指令:C i j。该指令意思是,询问电脑,杨威利的第i号战舰与第j号战舰当前是否在同一列中,如果在同一列中,那么它们之间布置有多少战舰。 
         作为一个资深的高级程序设计员,你被要求编写程序分析杨威利的指令,以及回答莱因哈特的询问。 
    最终的决战已经展开,银河的历史又翻过了一页……

    输入

    输入的第一行有一个整数T(1<=T<=500,000),表示总共有T条指令。 
    以下有T行,每行有一条指令。指令有两种格式: 
    1.M i j :i和j是两个整数(1<=i , j<=30000),表示指令涉及的战舰编号。该指令是莱因哈特窃听到的杨威利发布的舰队调动指令,并且保证第i号战舰与第j号战舰不在同一列。 
    2.C i j :i和j是两个整数(1<=i , j<=30000),表示指令涉及的战舰编号。该指令是莱因哈特发布的询问指令。

    输出

           你的程序应当依次对输入的每一条指令进行分析和处理: 
           如果是杨威利发布的舰队调动指令,则表示舰队排列发生了变化,你的程序要注意到这一点,但是不要输出任何信息; 
          如果是莱因哈特发布的询问指令,你的程序要输出一行,仅包含一个整数,表示在同一列上,第i号战舰与第j号战舰之间布置的战舰数目。如果第i号战舰与第j号战舰当前不在同一列上,则输出-1。

    样例输入

    4
    M 2 3
    C 1 2
    M 2 4
    C 4 2

    样例输出

       -1

     1

    思路:题目的两个指令摆明了是并查集。和普通的并查集区别的是查询时需要输出查询两舰之间的舰数。这就要求了合并时要有序,但线性不优化的并查集肯定会超时,于是可以用一个数组s来储存当前战舰的权值,在每次合并时更新i列舰队的头的权值和父结点。在每次执行search操作时更新其他节点的权值和父结点。代码中b数组为当前列的集合大小,方便更新权值。

    代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 3e4;
     4 int f[maxn+5], s[maxn+5], b[maxn+5];
     5 
     6 void init();
     7 int search(int);
     8 void merge(int, int);
     9 
    10 int main()
    11 {
    12     int T;
    13     scanf("%d
    ",&T);
    14     char op;
    15     int x, y;
    16     init();
    17     while (T--)
    18     {
    19         scanf("%c %d %d
    ",&op, &x, &y);
    20         if (op == 'M')
    21         {
    22             merge(x, y);
    23         }
    24         else if (op == 'C')
    25         {
    26             if (search(x) == search(y))
    27             {
    28                 printf("%d
    ",abs(s[x] - s[y]) - 1);
    29             }
    30             else
    31             {
    32                 printf("-1
    ");
    33             }
    34         }
    35     }
    36     return 0;
    37 }
    38 void init()
    39 {
    40     for (int i=1; i<=maxn; i++)
    41         f[i] = i, b[i] = 1, s[i] = 0;
    42 }
    43 int search(int x)
    44 {
    45     if (f[x] == x)
    46         return x;
    47     int k = f[x];
    48     f[x] = search(f[x]);
    49     s[x] += s[k];
    50     b[x] = b[f[x]];
    51     return f[x];
    52 }
    53 void merge(int x, int y)
    54 {
    55     int fx = search(x);
    56     int fy = search(y);
    57     f[fx] = fy;
    58     s[fx] += b[fy];
    59     b[fx] += b[fy];
    60     b[fy] = b[fx];
    61 }
    View Code

    2、破译密文

    题目描述

    信息的明文是由0和1组成的非空序列。但在网络通信中,为了信息的安全性,常对明文进行加密,用密文进行传输。密文是由0、1和若干个密码字母组成,每个密码字母代表不超过100位不同的01串,例如,密文=011a0bf00a01。密码破译的关键是确定每个密码的含义。

              经过长期统计分析,现在知道了每个密码的固定长度,如今,我方又截获了敌方的两段密文S1和S2,并且知道S1=S2,即两段密文代表相同的明文。你的任务是帮助情报人员对给定的两段密文进行分析,看一看有多少种可能的明文,保证密文是合法的,不用判错。

     

    输入

    第一行为一个字符串s1

    第二行为字符串s2

    第三行为整数n,表示有n个小写字母(0<n<=26)

    接着n行,每行为一个字符和一个整数,字符的长度


    输出

    为一行,为共有多少中明文的可能


    样例输入

    100ad1
    cc1
    4
    a 2
    d 3
    c 4
    b 50

     

    样例输出

    2

     思路:把每个字母拆分成与其等长的字串,例如c1,c2,c3,c4,再一一对应将每一对对应的字符并入同一个集合,最后和0同集合的就是0,和1同集合的就是1,其他集合就是未知的,可以是0或1,答案就是2的未知集合数次方。因为我做的题目明确表示保证密文是合法的,但我在别的地方看到的题目并没有保证密文合法,所以补充判断密文不合法的要点:1、字符串不等长2、某两个有明确指定的对应字符不相同(即一个是1一个是0)。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 10010;
     4 char c, s1[maxn], s2[maxn];
     5 int n, l[27], cnt, zj[27][110], f[maxn];
     6 bool vis[maxn];
     7 vector <int> t1, t2;
     8 
     9 int find(int x);
    10 void deal(char *s, int &len, vector <int> &a);
    11 void init(int n);
    12 
    13 int main()
    14 {
    15     ios::sync_with_stdio(false);
    16     cnt = 1;
    17     cin >> s1 >> s2 >> n;
    18     int l1 = strlen(s1), l2 = strlen(s2);
    19     for (int i=1; i<=n; i++)
    20     {
    21         cin >> c;
    22         cin >> l[c - 'a'];
    23         for (int j=1; j<=l[c - 'a']; j++)
    24         {
    25             zj[c - 'a'][j] = ++cnt;
    26         }
    27     }
    28     deal(s1, l1, t1);
    29     deal(s2, l2, t2);
    30     init(cnt);
    31     for (int i=0;i<l1;i++) {
    32         int x = t1[i], y = t2[i], fx = find(x), fy = find(y);
    33         if (fx != fy)
    34         {
    35             if (fx == 1 || fx == 0)
    36                 f[fy] = fx;
    37             else
    38                 f[fx] = fy;
    39         }
    40     }
    41 
    42     int ans = 0;
    43     for (int i=2;i<=cnt;i++)
    44         if (f[i] == i && vis[i]) ans++;
    45     cout << (1 << ans) << endl;
    46     return 0;
    47 }
    48 
    49 int find(int x)
    50 {
    51     if (f[x] == x)
    52         return x;
    53     f[x] = find(f[x]);
    54     return f[x];
    55 }
    56 void deal(char *s, int &len, vector <int> &a)
    57 {
    58     for (int i=0; i<=len; i++)
    59     {
    60         if (s[i] == '0' || s[i] == '1')
    61             a.push_back(s[i]-'0');
    62         else
    63             for (int j=1; j<=l[s[i]-'a']; j++)
    64             {
    65                 vis[zj[s[i]-'a'][j]] = true;
    66                 a.push_back(zj[s[i]-'a'][j]);
    67             }
    68     }
    69     len = a.size();
    70 }
    71 void init(int n)
    72 {
    73     for (int i=0;i<=n;i++) {
    74         f[i] = i;
    75     }
    76 }
    View Code
  • 相关阅读:
    1、怎么通过postman创建mock服务?
    13、使用正则表达式完成添加投资项目接口
    12、登录接口实战
    11、简历编写
    下载HTMLTestRunner 地址
    selenium (二)
    python 自动化测试
    Linux 安装MySQL流程
    文件 open 方法
    面向对象知识总结
  • 原文地址:https://www.cnblogs.com/FantaDevourer/p/12676365.html
Copyright © 2011-2022 走看看