• 1013 Battle Over Cities (25分)


    题意

    给定一个无向图并规定,当删除图中的某个顶点时,将会同时把与之连接的边一起删除。接下来给出k个查询,每个查询给出一个欲删除的顶点编号,求删除该顶点(和与其连接的边)后需要增加多少条边,才能使图变为连通(注: k次查询均在原图上进行)。

    思路

    注意是无向图

    上来直接写了个暴力的代码,改了无向图的bug后交一发直接AC了???

    暴力思路挺简单的,分别删除(1~n)号点后剩余的连通块数,不必真的删除,每次访问删除点时跳过就好了,然后每次的答案就是连通块数减一。

    不过数据范围确实小,求连通块的复杂度是:(mathcal O(n+m)),这样总的复杂度就是(mathcal O(qm))(color{green}{AcWing})上给的范围是(3500000)

    const int N=1010;
    vector<int> g[N];
    bool vis[N];
    int n,m,q;
    
    void dfs(int u,int x)
    {
        vis[u]=true;
        for(int i=0;i<g[u].size();i++)
        {
            int j=g[u][i];
            if(j == x || vis[j]) continue;
            dfs(j,x);
        }
    }
    
    int main()
    {
        cin>>n>>m>>q;
    
        while(m--)
        {
            int a,b;
            cin>>a>>b;
            g[a].pb(b);
            g[b].pb(a);
        }
    
        while(q--)
        {
            memset(vis,0,sizeof vis);
            int x;
            cin>>x;
    
            int cnt=0;
            for(int i=1;i<=n;i++)
                if(!vis[i] && i != x)
                {
                    dfs(i,x);
                    cnt++;
                }
    
            cout<<cnt-1<<endl;
        }
        //system("pause");
        return 0;
    }
    

    当然,既然是求连通块,那怎么能少的了并查集捏。只要不合并删除点和领接点就行了。

    const int N=1010;
    struct Edge{
        int a,b;
    }e[N*N];
    int p[N];
    int n,m,q;
    
    int find(int x)
    {
        if(x != p[x]) p[x]=find(p[x]);
        return p[x];
    }
    
    int main()
    {
        cin>>n>>m>>q;
    
        for(int i=0;i<m;i++)
        {
            int a,b;
            cin>>a>>b;
            e[i]={a,b};
        }
    
        while(q--)
        {
            for(int i=1;i<=n;i++) p[i]=i;
            
            int x;
            cin>>x;
    
            int cnt=0;
            for(int i=0;i<m;i++)
            {
                int a=e[i].a,b=e[i].b;
                if(a != x && b != x)
                {
                    int pa=find(a),pb=find(b);
                    p[pa]=pb;
                }
            }
            
            for(int i=1;i<=n;i++)
                if(p[i] == i && i != x)
                    cnt++;
            cout<<cnt-1<<endl;
        }
        //system("pause");
        return 0;
    }
    
  • 相关阅读:
    Linux文件名匹配
    Linux的常用命令
    百度飞桨学习笔记【Windows下用anaconda安装飞桨】
    在python中调用shell命令获得返回值
    使用sratoolkit下载NCBI数据
    perl 打开gz压缩文件 输出gz压缩文件
    jupyter notebook安装教程,打开ipynb文件
    生物信息学相关网站和博客资源
    R的循环补齐功能
    perl 遍历目录并且对目录中的文件进行操作
  • 原文地址:https://www.cnblogs.com/fxh0707/p/14228340.html
Copyright © 2020-2023  润新知