首页 > 其他分享 >并查集+建图 同样是逆向思维 和星球大战类似

并查集+建图 同样是逆向思维 和星球大战类似

时间:2024-02-26 19:49:20浏览次数:25  
标签:连通 星球大战 destory int 城市 查集 father 建图 摧毁

L2-013 红色警报 分数 25 作者 陈越 单位 浙江大学

战争中保持各个城市间的连通性非常重要。本题要求你编写一个报警程序,当失去一个城市导致国家被分裂为多个无法连通的区域时,就发出红色警报。注意:若该国本来就不完全连通,是分裂的k个区域,而失去一个城市并不改变其他城市之间的连通性,则不要发出警报。

意思就是1个连通块,如果删掉x后就出现多个连通块了,那就是红色警报。如果删除x后,连通块个数不变,那是普通警报(不要发出警报,下面写成普通警报了,没办法了)

比如1 - 0 - 3 删除0 发出红色警报   1-0-3删除1发普通警报   

输入格式:

输入在第一行给出两个整数N(0 < N ≤ 500)和M(≤ 5000),分别为城市个数(于是默认城市从0到N-1编号)和连接两城市的通路条数。随后M行,每行给出一条通路所连接的两个城市的编号,其间以1个空格分隔。在城市信息之后给出被攻占的信息,即一个正整数K和随后的K个被攻占的城市的编号。

注意:输入保证给出的被攻占的城市编号都是合法的且无重复,但并不保证给出的通路没有重复。

输出格式:

对每个被攻占的城市,如果它会改变整个国家的连通性,则输出Red Alert: City k is lost!,其中k是该城市的编号;否则只输出City k is lost.即可。如果该国失去了最后一个城市,则增加一行输出Game Over.

输入样例:

5 4
0 1
1 3
3 0
0 4
5
1 2 0 4 3

输出样例:

City 1 is lost.
City 2 is lost.
Red Alert: City 0 is lost!
City 4 is lost.
City 3 is lost.
Game Over.
 /*         连通状态用并查集表示,并查集没法删除元素,         采用逆向思维,从全摧毁开始一个一个恢复,全摧毁时的状态反应了摧毁第destory[k-1]个城市后的情况(摧毁是一个连续的过程,摧毁第destory[k-1]个意味着k-1前面的都以摧毁),恢复destory[k-1]城市后的连通状态是摧毁destory[k-2]城市的情况,恢复destory[1]城市后是摧毁destory[0]城市的情况,恢复destory[0]后是所有城市的连通状态。         恢复一个城市就遍历该点的邻居,并记录与该城市连接的连通块个数,             如果>1,那该破坏的城市就连接了多个连通块,也就是题目中的红色警报。(单点也算一个连通块)             如果=1,就是该城市只连接一个连通块,删除不影响其他连通块之间的通讯,也就是题目的普通警报             如果=0,那就是该城市是一个孤立的,没与其他城市连接,也是普通警报     eg:         比如有0 1 2 3 4 5六个城市,以及一些边         现在依次摧毁2 4 0城市         逆向看,先吧2 4 0全去掉,建立连通分量,假设有[1,3] [5]         恢复0,假设有边(0,2),(0,5)(0,3),那0 2不管,因为2摧毁了,     (0 5)合并,并记录5的代表元素 (0 3)合并,记录3的代表元素。发现与0有两个连通分量连接     合并之后就是[0,1,3,5],于是可以看出摧毁0城市后[1,3]和[5]没法连通,所以红色警报         恢复4,现在的连通分量是[0,1,3,5],假设有边(4,1)(4,5),遍历邻居代表元素只有一个,说明4城市只连一个连通分量     摧毁它不影响。合并之后是[0,1,3,5,4]         恢复2,现在的连通分量是[0,1,3,5,4],假设2没有与这些城市的边,那只会为它建立一个单点连通分量     与它连接的连通分量个数为0,也是普通警报     */
#include <iostream>
#include <cmath>
#include <vector>
#include <map>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <set>

using namespace std;

vector<vector<int>> G;

unordered_map<int, int> father;
int findN(int a)
{
    if (a != father[a])
        father[a] = findN(father[a]);
    return father[a];
}
void unionSet(int a, int b)
{
    if (!father.count(a))
        father[a] = a;
    if (!father.count(b))
        father[b] = b;
    father[findN(a)] = findN(b);
}

int main()
{
    int m, n;
    cin >> m >> n;

    // 建图
    for (int i = 0; i < m; i++)
        G.push_back(vector<int>());
    int a, b;
    for (int i = 0; i < n; i++) //注意是无向图
    {
        cin >> a >> b;
        G[a].push_back(b);
        G[b].push_back(a);
    }

    // 读入摧毁的城市
    int k;
    cin >> k;
    vector<int> destory(k);
    unordered_set<int> flagdes; // 标记摧毁的城市,因为要判断邻居是不是正常城市
    for (int i = 0; i < k; i++)
    {
        cin >> destory[i];
        flagdes.insert(destory[i]);
    }

    // 建立 给出的k个城市全部摧毁时 的连通状态
    bool isover = 0;
    if (destory.size() == m)
        isover = 1;
    for (int i = 0; i < m; i++)
    {
        if (!flagdes.count(i))
        {
            father[i] = i;  //如果是孤立的一个点,单独建立一个集合
            // 遍历邻居,找未摧毁的城市union
            for (int j = 0; j < G[i].size(); j++)
            {
                if (!flagdes.count(G[i][j]))
                {
                    unionSet(i, G[i][j]);
                }
            }
        }
    }

    // 恢复destroy[i],判断摧毁它后是什么情况
    unordered_map<int, int> flag; // 0-普通警报 1-红色警报
    for (int i = k - 1; i >= 0; i--)
    {
        father[destory[i]] = destory[i];//恢复成单点连通分量
        unordered_set<int> liantong; // 看恢复的这个城市与几个连通块相连,如果大于1个,那摧毁时就是红色 否则是普通
        for (int j = 0; j < G[destory[i]].size(); j++)
        {
            if (!flagdes.count(G[destory[i]][j]))
            {
                liantong.insert(findN(G[destory[i]][j]));
                unionSet(destory[i], G[destory[i]][j]); // 恢复,加入到连通分量里
            }
        }
        if (liantong.size() > 1)
            flag[destory[i]] = 1;
        else
            flag[destory[i]] = 0;
        flagdes.erase(destory[i]); // 注意,恢复的城市去除标记
    }

    for (int i = 0; i < k; i++)
    {
        if (flag[destory[i]] == 0)
        {
            cout << "City " << destory[i] << " is lost." << endl;
        }
        else
        {
            cout << "Red Alert: City " << destory[i] << " is lost!" << endl;
        }
    }
    if (isover)
    {
        cout << "Game Over." << endl;
    }
}

 

标签:连通,星球大战,destory,int,城市,查集,father,建图,摧毁
From: https://www.cnblogs.com/fyjie/p/18035018

相关文章

  • P1197 [JSOI2008] 星球大战
    原题链接题解,请看题解区第一篇,看一遍就会了code#include<bits/stdc++.h>usingnamespacestd;intfa[400005]={0};intfinds(intnow){returnfa[now]=(fa[now]==now?now:finds(fa[now]));}vector<int>G[400005];intbroke[400005];intBroke[400005]={0};intm......
  • 并查集
    作用:1.将两个集合合并2.询问两个元素是否在一个集合当中基本原理:每个集合用一棵树来表示,树根的编号就是整个集合的编号。每个节点存储它的父节点,p[x]表示x的父节点操作:1.判断树根:if(p[x]==x);2.求x的集合编号:while(p[x]!=x)x=p[x];3.如何合并两个集合:p[x]是x的集合编......
  • linux(ubuntu22.04)+PicGo(gui版)+阿里云oss搭建图床教程
    linux(ubuntu22.04)+PicGo(gui版)+阿里云oss搭建图床教程资源库PicGo下载链接:山东镜像源github原版阿里云oss链接linux下PicGo(gui版)的安装从资源库链接里下载后缀为.AppImage的安装包,版本可以选择稳定版2.3.1也可以用更新的beta版。修改文件权限,打开文......
  • ABC302Ex Ball Collector (可撤销并查集)
    由于博客园存在关站风险,文章以后同步发在这里,可能会有更好的阅读体验。首先我们分析一下,如果我们已经知道了要走哪些点,我们可以怎么做。考虑将\(a_i,b_i\)之间连边,发现题目可以被转化为给定一个图,要求对于每条边将其一个顶点染色,问最多能将多少个点染色。于是我们对于每个连......
  • P3367 【模板】并查集
    原题链接并查集模板练手。递归版本#include<bits/stdc++.h>usingnamespacestd;constintN=1e4+5;intfather[N];intfind(intmid){if(father[mid]!=mid){father[mid]=find(father[mid]);}returnfather[mid];}voidunion_fa(intx,inty){......
  • 集合问题——并查集
    目录问题引入算法原理参考代码问题引入给出n个人的m个关系,表示给出的两个人都是朋友关系,之后进行k次询问,要求判断给出的两人是否是朋友关系,朋友的朋友也是朋友算法原理简单来说就是对集合的合并进行一个处理,使得是朋友的一群人用一个共同的朋友记录,这样在查询的时候就可以通过......
  • 连续性区间位置查询——链式并查集
    目录问题概述思路分析参考代码做题总结问题概述这里给出两个题目,一个是上一篇的新春漫步(其实当时给的官方题解就是链式并查集的写法,但是当时我懒得写了,emmm),二是最近vp的一场cf_div3_923场的d题,准确来说,就是因为这个我才准备写这个的,题目大概就是给出一个长度为n的数组和q组询......
  • 并查集
    一、并查集的概念并查集是一种管理元素分组情况的数据结构,主要实现以下两个功能:查询元素\(a\)和\(b\)是否在同一集合合并元素\(a\)和\(b\)所在的集合注:并查集只能进行合并操作,不能进行分割操作。二、并查集的实现一般,我们采用数组par[]和height[]来实现并查......
  • 并查集
    【并查集是什么】并查集是用来表示一些不相交集合的算法。它可以很快地处理两个点之间是否在一个连通块中。【并查集的特点】动态合并集合;合并之后就不能拆开了。并查集开始前,先按顺序把初始集合编号。(初始也不一定每个都是单个元素)【并查集的实现】数据结构分类:抽......
  • 并查集
    记录21:042024-2-3目录1.并查集题目记录1.并查集用来快速元素是否属于同一组的数据结构利用路径压缩和按秩合并防止结构退化点击查看代码#defineMAX_N10000intpar[MAX_N];intrank[MAX_N];voidinit(intn){for(inti=0;i<n;i++){par[i]=......