玲珑学院OJ 1020 Grand Master【思维+并查集】

本文介绍了一道关于恐怖分子摧毁城市的算法题目,采用逆序思维和并查集的方法解决复杂的城市摧毁顺序问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1020 - Grand Master

Time Limit:2s Memory Limit:64MByte

Submissions:213Solved:41

DESCRIPTION

Eric, the famous terrorist, wants to destroy all the cities in Byteland. There are nn cities numbered from 11 to nn in Byteland. Also there are mm roads connecting the cities. One can go from city uiui to vivi (and vise versa) using the ii-th road.

Eric sends nn robots in the ss-th city. The ii-th robot will go to destroy the ii-th city. If the ii-th city is destroyed, all the roads directly connected with the ii-th city will also be destroyed. The robot will not use the destroyed roads. If the ii-th robot cannot reach the ii-th city, it will just return to the ss-city.

Eric wants to know which cities will be destroyed, if he sends the (i+1)(i+1)-th robot only after the ii-th city is destroyed or the ii-th robot returns to the ss-th city.

INPUT
There are multiple test cases. The first line of input contains an integer TT, indicating the number of test cases. For each test case:The first line contains three integers nn, mm and ss (1n105,1m2×105,1kn)(1≤n≤105,1≤m≤2×105,1≤k≤n).Each of the next mm lines contains two integers uiui and vivi (1ui,vin,uivi)(1≤ui,vi≤n,ui≠vi).
OUTPUT
For each test case, output the destroyed cities in increasing order.
SAMPLE INPUT
1
5 6 5
1 2
4 3
1 5
3 5
3 1
4 3
SAMPLE OUTPUT
1 3 5

题目大意:


一共有N个机器人,编号为i的机器人的目的是去拆毁i号城市,按照顺序(1~n)去派出机器人,当城市i被拆毁的时候,对应和城市i相连的边也会被拆毁。

这个图是一个无向图,共有N个点,M条边。

问你能够拆毁的城市的编号(需求从小到大排序)


思路:


1、我们如果按照顺序去派出机器人,那么拆边的操作相对比较复杂,我们不妨将拆变成建。

采用一种逆序思维去搞这个题。

那么我们从n到1去枚举点,按照枚举出来的点开始建边,如果一个点能够建出来一条道路通向起点,那么对应这个点就能够被拆毁。


2、那么每一次对应枚举出来的当前点i,如果与i相连的点中,有编号大于i的才能够走,所以我们不妨将这样的边通过并查集进行建立。

那么对于一轮结束之后,有find(i)==find(起点)的点i,就是答案中的一员。


3、过程维护,注意输出格式即可。


Ac代码:


#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
vector<int >mp[100500];
int ans[100500];
int f[100500];
int n,m,ss;
int find(int a)
{
    int r=a;
    while(f[r]!=r)
    r=f[r];
    int i=a;
    int j;
    while(i!=r)
    {
        j=f[i];
        f[i]=r;
        i=j;
    }
    return r;
}
int merge(int a,int b)
{
    int A,B;
    A=find(a);
    B=find(b);
    if(A!=B)
    {
        f[B]=A;
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&ss);
        for(int i=1;i<=n;i++)mp[i].clear();
        for(int i=0;i<m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            mp[x].push_back(y);
            mp[y].push_back(x);
        }
        int ff=0;
        for(int i=1;i<=n;i++)f[i]=i;
        for(int i=n;i>=1;i--)
        {
            int x=find(i);
            for(int j=0;j<mp[i].size();j++)
            {
                int v=mp[i][j];
                if(v>i)
                {
                    int y=find(v);
                    if(x!=y)
                    {
                        merge(x,y);
                    }
                }
            }
            int y=find(ss);
            if(x==y)
            {
                ans[i]=1;
            }
            else ans[i]=0;
        }
        for(int i=1;i<=n;i++)
        {
            if(ans[i]==1)
            {
                if(ff==0)printf("%d",i),ff=1;
                else printf(" %d",i);
            }
        }
        printf("\n");
    }
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值